Author: bms
Date: Wed Mar  4 02:09:12 2009
New Revision: 189340
URL: http://svn.freebsd.org/changeset/base/189340

Log:
  Add full SSM stack support to mtest(8) diagnostic tool.

Modified:
  head/usr.sbin/mtest/mtest.c

Modified: head/usr.sbin/mtest/mtest.c
==============================================================================
--- head/usr.sbin/mtest/mtest.c Wed Mar  4 02:08:20 2009        (r189339)
+++ head/usr.sbin/mtest/mtest.c Wed Mar  4 02:09:12 2009        (r189340)
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2007 Bruce M. Simpson.
+ * Copyright (c) 2007-2009 Bruce Simpson.
  * Copyright (c) 2000 Wilbert De Graaf.
  * All rights reserved.
  *
@@ -55,26 +55,21 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <unistd.h>
 
-/* The following two socket options are private to the kernel and libc. */
-
-#ifndef IP_SETMSFILTER
-#define IP_SETMSFILTER 74 /* atomically set filter list */
-#endif
-#ifndef IP_GETMSFILTER
-#define IP_GETMSFILTER 75 /* get filter list */
-#endif
-
 static void    process_file(char *, int);
 static void    process_cmd(char*, int, FILE *fp);
 static void    usage(void);
-#ifdef WITH_IGMPV3
-static int     inaddr_cmp(const void *a, const void *b);
-#endif
 
 #define        MAX_ADDRS       20
 #define        STR_SIZE        20
 #define        LINE_LENGTH     80
 
+static int
+inaddr_cmp(const void *a, const void *b)
+{
+       return ((int)((const struct in_addr *)a)->s_addr -
+           ((const struct in_addr *)b)->s_addr);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -145,17 +140,13 @@ process_cmd(char *cmd, int s, FILE *fp _
        char                     str1[STR_SIZE];
        char                     str2[STR_SIZE];
        char                     str3[STR_SIZE];
-#ifdef WITH_IGMPV3
-       char                     filtbuf[IP_MSFILTER_SIZE(MAX_ADDRS)];
-#endif
+       struct in_addr           sources[MAX_ADDRS];
        struct ifreq             ifr;
        struct ip_mreq           imr;
        struct ip_mreq_source    imrs;
-#ifdef WITH_IGMPV3
-       struct ip_msfilter      *imsfp;
-#endif
        char                    *line;
-       int                      n, opt, f, flags;
+       uint32_t                 fmode;
+       int                      i, n, opt, f, flags;
 
        line = cmd;
        while (isblank(*++line))
@@ -181,20 +172,51 @@ process_cmd(char *cmd, int s, FILE *fp _
 
        case 'j':
        case 'l':
-               sscanf(line, "%s %s", str1, str2);
-               if (((imr.imr_multiaddr.s_addr = inet_addr(str1)) ==
-                   INADDR_NONE) ||
-                   ((imr.imr_interface.s_addr = inet_addr(str2)) ==
-                   INADDR_NONE)) {
-                       printf("-1\n");
-                       break;
+               str3[0] = '\0';
+               sscanf(line, "%s %s %s", str1, str2, str3);
+               if ((imrs.imr_sourceaddr.s_addr = inet_addr(str3)) !=
+                   INADDR_NONE) {
+                       /*
+                        * inclusive mode join with source, possibly
+                        * on existing membership.
+                        */
+                       if (((imrs.imr_multiaddr.s_addr = inet_addr(str1)) ==
+                           INADDR_NONE) ||
+                           ((imrs.imr_interface.s_addr = inet_addr(str2)) ==
+                           INADDR_NONE)) {
+                               printf("-1\n");
+                               break;
+                       }
+                       opt = (*cmd == 'j') ? IP_ADD_SOURCE_MEMBERSHIP :
+                           IP_DROP_SOURCE_MEMBERSHIP;
+                       if (setsockopt( s, IPPROTO_IP, opt, &imrs,
+                           sizeof(imrs)) != 0) {
+                               warn("setsockopt %s", (*cmd == 'j') ?
+                                   "IP_ADD_SOURCE_MEMBERSHIP" :
+                                   "IP_DROP_SOURCE_MEMBERSHIP");
+                       } else {
+                               printf("ok\n");
+                       }
+               } else {
+                       /* exclusive mode join w/o source. */
+                       if (((imr.imr_multiaddr.s_addr = inet_addr(str1)) ==
+                           INADDR_NONE) ||
+                           ((imr.imr_interface.s_addr = inet_addr(str2)) ==
+                           INADDR_NONE)) {
+                               printf("-1\n");
+                               break;
+                       }
+                       opt = (*cmd == 'j') ? IP_ADD_MEMBERSHIP :
+                           IP_DROP_MEMBERSHIP;
+                       if (setsockopt( s, IPPROTO_IP, opt, &imr,
+                           sizeof(imr)) != 0) {
+                               warn("setsockopt %s", (*cmd == 'j') ?
+                                   "IP_ADD_MEMBERSHIP" :
+                                   "IP_DROP_MEMBERSHIP");
+                       } else {
+                               printf("ok\n");
+                       }
                }
-               opt = (*cmd == 'j') ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP;
-               if (setsockopt( s, IPPROTO_IP, opt, &imr,
-                   sizeof(imr)) != 0)
-                       warn("setsockopt IP_ADD_MEMBERSHIP/IP_DROP_MEMBERSHIP");
-               else
-                       printf("ok\n");
                break;
 
        case 'a':
@@ -233,6 +255,7 @@ process_cmd(char *cmd, int s, FILE *fp _
                printf("warning: IFF_ALLMULTI cannot be set from userland "
                    "in FreeBSD; command ignored.\n");
                break;
+
        case 'p':
                if (sscanf(line, "%s %u", ifr.ifr_name, &f) != 2) {
                        printf("-1\n");
@@ -257,7 +280,6 @@ process_cmd(char *cmd, int s, FILE *fp _
                        printf( "changed to 0x%08x\n", flags );
                break;
 
-#ifdef WITH_IGMPV3
        /*
         * Set the socket to include or exclude filter mode, and
         * add some sources to the filterlist, using the full-state,
@@ -265,42 +287,38 @@ process_cmd(char *cmd, int s, FILE *fp _
         */
        case 'i':
        case 'e':
-               /* XXX: SIOCSIPMSFILTER will be made an internal API. */
+               n = 0;
+               fmode = (*cmd == 'i') ? MCAST_INCLUDE : MCAST_EXCLUDE;
                if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
                        printf("-1\n");
                        break;
                }
-               imsfp = (struct ip_msfilter *)filtbuf;
-               if (((imsfp->imsf_multiaddr.s_addr = inet_addr(str1)) ==
+               /* recycle imrs struct for convenience */
+               if (((imrs.imr_multiaddr.s_addr = inet_addr(str1)) ==
                    INADDR_NONE) ||
-                   ((imsfp->imsf_interface.s_addr = inet_addr(str2)) ==
-                   INADDR_NONE) || (n > MAX_ADDRS)) {
+                   ((imrs.imr_interface.s_addr = inet_addr(str2)) ==
+                   INADDR_NONE) || (n < 0 || n > MAX_ADDRS)) {
                        printf("-1\n");
                        break;
                }
-               imsfp->imsf_fmode = (*cmd == 'i') ? MCAST_INCLUDE :
-                   MCAST_EXCLUDE;
-               imsfp->imsf_numsrc = n;
                for (i = 0; i < n; i++) {
                        fgets(str1, sizeof(str1), fp);
-                       if ((imsfp->imsf_slist[i].s_addr = inet_addr(str1)) ==
+                       if ((sources[i].s_addr = inet_addr(str1)) ==
                            INADDR_NONE) {
                                printf("-1\n");
                                return;
                        }
                }
-               if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0)
-                       warn("setsockopt SIOCSIPMSFILTER");
+               if (setipv4sourcefilter(s, imrs.imr_interface,
+                   imrs.imr_multiaddr, fmode, n, sources) != 0)
+                       warn("getipv4sourcefilter");
                else
                        printf("ok\n");
                break;
-#endif /* WITH_IGMPV3 */
 
        /*
         * Allow or block traffic from a source, using the
         * delta based api.
-        * XXX: Currently we allow this to be used with the ASM-only
-        *      implementation of RFC3678 in FreeBSD 7. 
         */
        case 't':
        case 'b':
@@ -314,24 +332,14 @@ process_cmd(char *cmd, int s, FILE *fp _
                        printf("-1\n");
                        break;
                }
-
-#ifdef WITH_IGMPV3
-               /* XXX: SIOCSIPMSFILTER will be made an internal API. */
-               /* First determine out current filter mode. */
-               imsfp = (struct ip_msfilter *)filtbuf;
-               imsfp->imsf_multiaddr.s_addr = imrs.imr_multiaddr.s_addr;
-               imsfp->imsf_interface.s_addr = imrs.imr_interface.s_addr;
-               imsfp->imsf_numsrc = 5;
-               if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) {
-                       /* It's only okay for 't' to fail */
-                       if (*cmd != 't') {
-                               warn("ioctl SIOCSIPMSFILTER");
-                               break;
-                       } else {
-                               imsfp->imsf_fmode = MCAST_INCLUDE;
-                       }
+               /* First determine our current filter mode. */
+               n = 0;
+               if (getipv4sourcefilter(s, imrs.imr_interface,
+                   imrs.imr_multiaddr, &fmode, &n, NULL) != 0) {
+                       warn("getipv4sourcefilter");
+                       break;
                }
-               if (imsfp->imsf_fmode == MCAST_EXCLUDE) {
+               if (fmode == MCAST_EXCLUDE) {
                        /* Any source */
                        opt = (*cmd == 't') ? IP_UNBLOCK_SOURCE :
                            IP_BLOCK_SOURCE;
@@ -340,60 +348,37 @@ process_cmd(char *cmd, int s, FILE *fp _
                        opt = (*cmd == 't') ? IP_ADD_SOURCE_MEMBERSHIP :
                            IP_DROP_SOURCE_MEMBERSHIP;
                }
-#else /* !WITH_IGMPV3 */
-               /*
-                * Don't look before we leap; we may only block or unblock
-                * sources on a socket in exclude mode.
-                */
-               opt = (*cmd == 't') ? IP_UNBLOCK_SOURCE : IP_BLOCK_SOURCE;
-#endif /* WITH_IGMPV3 */
                if (setsockopt(s, IPPROTO_IP, opt, &imrs, sizeof(imrs)) == -1)
                        warn("ioctl 
IP_ADD_SOURCE_MEMBERSHIP/IP_DROP_SOURCE_MEMBERSHIP/IP_UNBLOCK_SOURCE/IP_BLOCK_SOURCE");
                else
                        printf("ok\n");
                break;
 
-#ifdef WITH_IGMPV3
        case 'g':
-               /* XXX: SIOCSIPMSFILTER will be made an internal API. */
                if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) {
                        printf("-1\n");
                        break;
                }
-               imsfp = (struct ip_msfilter *)filtbuf;
-               if (((imsfp->imsf_multiaddr.s_addr = inet_addr(str1)) ==
+               /* recycle imrs struct for convenience */
+               if (((imrs.imr_multiaddr.s_addr = inet_addr(str1)) ==
                    INADDR_NONE) ||
-                   ((imsfp->imsf_interface.s_addr = inet_addr(str2)) ==
+                   ((imrs.imr_interface.s_addr = inet_addr(str2)) ==
                    INADDR_NONE) || (n < 0 || n > MAX_ADDRS)) {
                        printf("-1\n");
                        break;
                }
-               imsfp->imsf_numsrc = n;
-               if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) {
-                       warn("setsockopt SIOCSIPMSFILTER");
+               if (getipv4sourcefilter(s, imrs.imr_interface,
+                   imrs.imr_multiaddr, &fmode, &n, sources) != 0) {
+                       warn("getipv4sourcefilter");
                        break;
                }
-               printf("%s\n", (imsfp->imsf_fmode == MCAST_INCLUDE) ?
-                   "include" : "exclude");
-               printf("%d\n", imsfp->imsf_numsrc);
-               if (n >= imsfp->imsf_numsrc) {
-                       n = imsfp->imsf_numsrc;
-                       qsort(imsfp->imsf_slist, n, sizeof(struct in_addr),
-                           &inaddr_cmp);
-                       for (i = 0; i < n; i++)
-                               printf("%s\n", inet_ntoa(imsfp->imsf_slist[i]));
-               }
-               break;
-#endif /* !WITH_IGMPV3 */
-
-#ifndef WITH_IGMPV3
-       case 'i':
-       case 'e':
-       case 'g':
-               printf("warning: IGMPv3 is not supported by this version "
-                   "of FreeBSD; command ignored.\n");
+               printf("%s\n", (fmode == MCAST_INCLUDE) ? "include" :
+                   "exclude");
+               printf("%d\n", n);
+               qsort(sources, n, sizeof(struct in_addr), &inaddr_cmp);
+               for (i = 0; i < n; i++)
+                       printf("%s\n", inet_ntoa(sources[i]));
                break;
-#endif /* WITH_IGMPV3 */
 
        case '\n':
                break;
@@ -407,31 +392,18 @@ static void
 usage(void)
 {
 
-       printf("j g.g.g.g i.i.i.i          - join IP multicast group\n");
-       printf("l g.g.g.g i.i.i.i          - leave IP multicast group\n");
+       printf("j g.g.g.g i.i.i.i [s.s.s.s] - join IP multicast group\n");
+       printf("l g.g.g.g i.i.i.i [s.s.s.s] - leave IP multicast group\n");
        printf("a ifname e.e.e.e.e.e       - add ether multicast address\n");
        printf("d ifname e.e.e.e.e.e       - delete ether multicast address\n");
        printf("m ifname 1/0               - set/clear ether allmulti flag\n");
        printf("p ifname 1/0               - set/clear ether promisc flag\n");
-#ifdef WITH_IGMPv3
        printf("i g.g.g.g i.i.i.i n        - set n include mode src filter\n");
        printf("e g.g.g.g i.i.i.i n        - set n exclude mode src filter\n");
-#endif
        printf("t g.g.g.g i.i.i.i s.s.s.s  - allow traffic from src\n");
        printf("b g.g.g.g i.i.i.i s.s.s.s  - block traffic from src\n");
-#ifdef WITH_IGMPV3
        printf("g g.g.g.g i.i.i.i n        - get and show n src filters\n");
-#endif
        printf("f filename                 - read command(s) from file\n");
        printf("s seconds                  - sleep for some time\n");
        printf("q                          - quit\n");
 }
-
-#ifdef WITH_IGMPV3
-static int
-inaddr_cmp(const void *a, const void *b)
-{
-       return((int)((const struct in_addr *)a)->s_addr -
-           ((const struct in_addr *)b)->s_addr);
-}
-#endif
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to