Part 3 of the MBIM patch updates ifconfig(8).

Index: sbin/ifconfig/ifconfig.8
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.8,v
retrieving revision 1.267
diff -u -p -u -p -r1.267 ifconfig.8
--- sbin/ifconfig/ifconfig.8    6 Apr 2016 10:07:14 -0000       1.267
+++ sbin/ifconfig/ifconfig.8    23 May 2016 09:50:08 -0000
@@ -519,6 +519,8 @@ tunnel
 .Xr vxlan 4 )
 .It
 .Xr vlan 4
+.It
+.Xr mbim 4
 .El
 .\" BRIDGE
 .Sh BRIDGE
@@ -1645,6 +1647,71 @@ will be assigned 802.1Q tag 5.
 Disassociate from the parent interface.
 This breaks the link between the vlan interface and its parent,
 clears its vlan tag, flags, and link address, and shuts the interface down.
+.El
+.\" MBIM
+.Sh MBIM
+.nr nS 1
+.Bk -words
+.Nm ifconfig
+.Ar mbim-interface
+.Op Cm pin Ar pin
+.Op Cm chgpin Ar oldpin Ar newpin
+.Op Cm puk Ar puk Ar newpin
+.Op Oo Fl Oc Ns Cm apn Ar apn
+.Op Oo Fl Oc Ns Cm class Ar class,class,...
+.Op Oo Fl Oc Ns Cm roaming
+.Ek
+.nr nS 0
+.Pp
+The following options are available for an
+.Xr mbim 4
+interface:
+.Bl -tag -width Ds
+.It Cm pin Ar pin
+Enter the PIN required to unlock the SIM card. Most SIM cards will not
+allow to establish a network association without providing a PIN.
+.It Cm chgpin Ar oldpin Ar newpin
+Permanently changes the PIN of the SIM card from the current value
+.Ar oldpin
+to
+.Ar newpin .
+.It Cm puk Ar puk Ar newpin
+Sets the PIN of the SIM card to
+.Ar newpin
+using the PUK
+.Ar puk
+to validate the request.
+.It Cm apn Ar apn
+Set the "Access Point Name" required by your network provider.
+.It Fl apn
+Clear the current "Access Point Name" value.
+.It Cm class
+List all available cell classes.
+.It Cm class Ar class,class,...
+Set the preferred cell classes. Apart from those listed by
+.Nm Cm class
+the following aliases can be used:
+.Ar 4G,
+.Ar 3G,
+and
+.Ar 2G.
+.It Fl class
+Clear any cell class preferences.
+.It Cm roaming
+Enable data roaming.
+.It Fl roaming
+Disable data roaming.
+.It Cm up
+As soon as the interface is marked as "up", the
+.Xr mbim 4
+device will try to establish a data connection with the service provider.
+.It Cm down
+Marking the interface as "down" will terminate any existing data connection
+and deregister with the service provider.
+.It Cm devinfo
+Provides some additional information about the
+.Xr mbim 4
+device, e.g. the IMEI number.
 .El
 .Sh EXAMPLES
 Assign the
Index: sbin/ifconfig/ifconfig.c
===================================================================
RCS file: /cvs/src/sbin/ifconfig/ifconfig.c,v
retrieving revision 1.322
diff -u -p -u -p -r1.322 ifconfig.c
--- sbin/ifconfig/ifconfig.c    3 May 2016 17:52:33 -0000       1.322
+++ sbin/ifconfig/ifconfig.c    23 May 2016 09:50:08 -0000
@@ -107,6 +107,8 @@
 #include <ifaddrs.h>
 
 #include "brconfig.h"
+#include <dev/usb/mbim.h>
+#include <dev/usb/if_mbim.h>
 
 #define MINIMUM(a, b)  (((a) < (b)) ? (a) : (b))
 #define MAXIMUM(a, b)  (((a) > (b)) ? (a) : (b))
@@ -143,8 +145,10 @@ int        Lflag = 1;
 
 int    showmediaflag;
 int    showcapsflag;
+int    showdevinfoflag;
 int    shownet80211chans;
 int    shownet80211nodes;
+int    showclasses;
 
 void   notealias(const char *, int);
 void   setifaddr(const char *, int);
@@ -275,6 +279,19 @@ void       unsetifdesc(const char *, int);
 void   printifhwfeatures(const char *, int);
 void   setpair(const char *, int);
 void   unsetpair(const char *, int);
+void   mbim_status(void);
+void   mbim_devinfo(const char *, int);
+void   mbim_printclasses(char *, int);
+int    mbim_parse_classes(const char *);
+void   mbim_setpin(const char *, int);
+void   mbim_chgpin(const char *, const char *);
+void   mbim_puk(const char *, const char *);
+void   mbim_pinop(int, int, const char *, const char *);
+void   mbim_apn(const char *, int);
+void   mbim_setclass(const char *, int);
+void   mbim_roaming(const char *, int);
+void   utf16_to_char(uint16_t *, int, char *, size_t);
+int    char_to_utf16(const char *, uint16_t *, size_t);
 #else
 void   setignore(const char *, int);
 #endif
@@ -486,6 +503,16 @@ const struct       cmd {
        { "-descr",     1,              0,              unsetifdesc },
        { "wol",        IFXF_WOL,       0,              setifxflags },
        { "-wol",       -IFXF_WOL,      0,              setifxflags },
+       { "devinfo",    NEXTARG0,       0,              mbim_devinfo },
+       { "pin",        NEXTARG,        0,              mbim_setpin },
+       { "chgpin",     NEXTARG2,       0,              NULL, mbim_chgpin },
+       { "puk",        NEXTARG2,       0,              NULL, mbim_puk },
+       { "apn",        NEXTARG,        0,              mbim_apn },
+       { "-apn",       -1,             0,              mbim_apn },
+       { "class",      NEXTARG0,       0,              mbim_setclass },
+       { "-class",     -1,             0,              mbim_setclass },
+       { "roaming",    1,              0,              mbim_roaming },
+       { "-roaming",   0,              0,              mbim_roaming },
        { "patch",      NEXTARG,        0,              setpair },
        { "-patch",     1,              0,              unsetpair },
 #else /* SMALL */
@@ -2898,6 +2925,8 @@ status(int link, struct sockaddr_dl *sdl
 #ifndef SMALL
        if (showcapsflag)
                printifhwfeatures(NULL, 1);
+       if (showdevinfoflag)
+               mbim_devinfo(NULL, 1);
 #endif
        if (sdl != NULL && sdl->sdl_alen &&
            (sdl->sdl_type == IFT_ETHER || sdl->sdl_type == IFT_CARP))
@@ -2942,6 +2971,7 @@ status(int link, struct sockaddr_dl *sdl
        mpe_status();
        mpw_status();
        pflow_status();
+       mbim_status();
 #endif
        trunk_status();
        getifgroups();
@@ -4875,6 +4905,438 @@ setifpriority(const char *id, int param)
        if (ioctl(s, SIOCSIFPRIORITY, (caddr_t)&ifr) < 0)
                warn("SIOCSIFPRIORITY");
 }
+
+
+const struct mbim_valdescr mbim_regstate[] = MBIM_REGSTATE_DESCRIPTIONS;
+const struct mbim_valdescr mbim_dataclass[] = MBIM_DATACLASS_DESCRIPTIONS;
+const struct mbim_valdescr mbim_simstate[] = MBIM_SIMSTATE_DESCRIPTIONS;
+const struct mbim_valdescr mbim_istate[] = MBIM_INTERNAL_STATE_DESCRIPTIONS;
+const struct mbim_valdescr mbim_pktstate[] = MBIM_PKTSRV_STATE_DESCRIPTIONS;
+const struct mbim_valdescr mbim_actstate[] = 
MBIM_ACTIVATION_STATE_DESCRIPTIONS;
+
+const struct mbim_valdescr mbim_classalias[] = {
+       { MBIM_DATACLASS_GPRS | MBIM_DATACLASS_EDGE, "2g" },
+       { MBIM_DATACLASS_UMTS | MBIM_DATACLASS_HSDPA | MBIM_DATACLASS_HSUPA,
+           "3g" },
+       { MBIM_DATACLASS_LTE, "4g" },
+       { 0, NULL }
+};
+
+int
+mbim_descr2val(const struct mbim_valdescr *vdp, char *str)
+{
+       while (vdp->descr != NULL) {
+               if (!strcasecmp(vdp->descr, str))
+                       return vdp->val;
+               vdp++;
+       }
+       return 0;
+}
+
+void
+mbim_status(void)
+{
+       struct mbim_info mi;
+       char     provider[MBIM_PROVIDERNAME_MAXLEN+1];
+       char     roamingtxt[MBIM_ROAMINGTEXT_MAXLEN+1];
+       int      n;
+
+       memset((char *)&mi, 0, sizeof(mi));
+       ifr.ifr_data = (caddr_t)&mi;
+       if (ioctl(s, SIOCGMBIMINFO, (caddr_t)&ifr) == -1)
+               return;
+
+       if (mi.nwerror) {
+               /* 3GPP 24.008 Cause Code */
+               printf("\terror: ");
+               switch (mi.nwerror) {
+               case 2:
+                       printf("SIM not activated");
+                       break;
+               case 4:
+                       printf("Roaming not supported");
+                       break;
+               case 6:
+                       printf("SIM reported stolen");
+                       break;
+               case 7:
+                       printf("No GPRS subscription");
+                       break;
+               case 8:
+                       printf("GPRS and non-GPRS services not allowed");
+                       break;
+               case 11:
+                       printf("Subscription expired");
+                       break;
+               case 12:
+                       printf("Subscription does not cover current location");
+                       break;
+               case 13:
+                       printf("No roaming in this location");
+                       break;
+               case 14:
+                       printf("GPRS not supported");
+                       break;
+               case 15:
+                       printf("No subscription for the service");
+                       break;
+               case 17:
+                       printf("Registration failed");
+                       break;
+               case 22:
+                       printf("Network congestion");
+                       break;
+               default:
+                       printf("Error code %d", mi.nwerror);
+                       break;
+               }
+               printf("\n");
+       }
+
+       printf("\tstate: %s (%s, %s)\n", mbim_val2descr(mbim_istate, mi.state),
+           mbim_val2descr(mbim_pktstate, mi.packetstate),
+           mbim_val2descr(mbim_actstate, mi.activation));
+       printf("\tpin: ");
+       switch (mi.pin_state) {
+       case MBIM_PIN_REQUIRED:
+               printf("required");
+               break;
+       case MBIM_PIN_UNLOCKED:
+               printf("valid");
+               break;
+       case MBIM_PUK_REQUIRED:
+               printf("locked (PUK required)");
+               break;
+       default:
+               printf("unkown state (%d)", mi.pin_state);
+               break;
+       }
+       if (mi.pin_attempts_left != MBIM_VALUE_UNKNOWN)
+               printf(" (%d attempts left)", mi.pin_attempts_left);
+       printf("\n");
+       printf("\troaming: %s\n", mi.enable_roaming ? "enabled" : "disabled");
+       printf("\tregistration: %s",
+           mbim_val2descr(mbim_regstate, mi.regstate));
+       utf16_to_char(mi.roamingtxt, MBIM_ROAMINGTEXT_MAXLEN,
+           roamingtxt, sizeof (roamingtxt));
+       if (roamingtxt[0])
+               printf(" [%s]", roamingtxt);
+       printf("\n");
+
+       utf16_to_char(mi.provider, MBIM_PROVIDERNAME_MAXLEN,
+           provider, sizeof (provider));
+       if (provider[0])
+               printf("\tprovider: %s\n", provider);
+
+       if (showclasses)
+               mbim_printclasses("available classes", mi.supportedclasses);
+       if (mi.preferredclasses != MBIM_DATACLASS_NONE)
+               mbim_printclasses("preferred classes", mi.preferredclasses);
+       printf("\tcell class: %s\n",
+           mbim_val2descr(mbim_dataclass, mi.highestclass));
+
+       if (mi.rssi != MBIM_VALUE_UNKNOWN && mi.rssi != 0)
+               printf("\trssi: %ddBm\n", mi.rssi);
+       switch (mi.ber) {
+       case MBIM_BER_EXCELLENT:
+               printf("\tber: excellent\n");
+               break;
+       case MBIM_BER_VERYGOOD:
+               printf("\tber: very good\n");
+               break;
+       case MBIM_BER_GOOD:
+               printf("\tber: good\n");
+               break;
+       case MBIM_BER_OK:
+               printf("\tber: ok\n");
+               break;
+       case MBIM_BER_MEDIUM:
+               printf("\tber: medium\n");
+               break;
+       case MBIM_BER_BAD:
+               printf("\tber: bad\n");
+               break;
+       case MBIM_BER_VERYBAD:
+               printf("\tber: very bad\n");
+               break;
+       case MBIM_BER_EXTREMELYBAD:
+               printf("\tber: extremely bad\n");
+               break;
+       default:
+               break;
+       }
+       if (mi.uplink_speed != 0 || mi.downlink_speed != 0) {
+               char s[2][FMT_SCALED_STRSIZE];
+               if (fmt_scaled(mi.uplink_speed, s[0]) != 0)
+                       snprintf(s[0], sizeof (s[0]), "%llu", mi.uplink_speed);
+               if (fmt_scaled(mi.downlink_speed, s[1]) != 0)
+                       snprintf(s[1], sizeof (s[1]), "%llu", 
mi.downlink_speed);
+               printf("\tspeed: %sps up %sps down\n", s[0], s[1]);
+       }
+       for (n = 0; n < MBIM_MAX_DNSSRV; n++) {
+               if (mi.ipv4dns[n] == INADDR_ANY)
+                       break;
+               printf("\tdns%d: %s\n", n,
+                   inet_ntoa(*(struct in_addr *)&mi.ipv4dns[n]));
+       }
+}
+
+void
+mbim_devinfo(const char *unused, int show)
+{
+       struct mbim_info mi;
+       char     devid[MBIM_DEVID_MAXLEN+1];
+       char     fwinfo[MBIM_FWINFO_MAXLEN+1];
+       char     hwinfo[MBIM_HWINFO_MAXLEN+1];
+       char     sid[MBIM_SUBSCRIBERID_MAXLEN+1];
+       char     iccid[MBIM_ICCID_MAXLEN+1];
+       char     apn[MBIM_APN_MAXLEN+1];
+       char     pn[MBIM_PHONENR_MAXLEN+1];
+       int      n;
+
+       if (!show) {
+               if (showdevinfoflag)
+                       usage(1);
+               showdevinfoflag = 1;
+               return;
+       }
+
+       memset((char *)&mi, 0, sizeof(mi));
+       ifr.ifr_data = (caddr_t)&mi;
+       if (ioctl(s, SIOCGMBIMINFO, (caddr_t)&ifr) == -1)
+               return;
+
+       utf16_to_char(mi.devid, MBIM_DEVID_MAXLEN, devid, sizeof (devid));
+       if (devid[0]) {
+               switch (mi.cellclass) {
+               case MBIM_CELLCLASS_GSM:
+                       printf("\tIMEI: ");
+                       break;
+               case MBIM_CELLCLASS_CDMA:
+                       n = strlen(devid);
+                       if (n == 8 || n == 11) {
+                               printf("\tESN: ");
+                               break;
+                       } else if (n == 14 || n == 18) {
+                               printf("\tMEID: ");
+                               break;
+                       }
+                       /*FALLTHROUGH*/
+               default:
+                       printf("\tID: ");
+                       break;
+               }
+               printf("%s\n", devid);
+       }
+       utf16_to_char(mi.hwinfo, MBIM_HWINFO_MAXLEN, hwinfo, sizeof (hwinfo));
+       if (hwinfo[0])
+               printf("\tdevice: %s\n", hwinfo);
+       utf16_to_char(mi.fwinfo, MBIM_FWINFO_MAXLEN, fwinfo, sizeof (fwinfo));
+       if (fwinfo[0])
+               printf("\tfirmware: %s\n", fwinfo);
+
+       utf16_to_char(mi.sid, MBIM_SUBSCRIBERID_MAXLEN, sid, sizeof (sid));
+       if (sid[0])
+               printf("\tsubscriber id: %s\n", sid);
+       utf16_to_char(mi.iccid, MBIM_ICCID_MAXLEN, iccid, sizeof (iccid));
+       if (iccid[0])
+               printf("\tICC id: %s\n", iccid);
+       printf("\tradio: hw %s, sw %s\n",
+           mi.hw_radio_on ? "on" : "off", mi.sw_radio_on ? "on" : "off");
+
+       printf("\tSIM: %s\n", mbim_val2descr(mbim_simstate, mi.sim_state));
+       utf16_to_char(mi.apn, MBIM_APN_MAXLEN, apn, sizeof (apn));
+       if (apn[0])
+               printf("\tAPN: %s\n", apn);
+       utf16_to_char(mi.pn, MBIM_PHONENR_MAXLEN, pn, sizeof (pn));
+       if (pn[0])
+               printf("\tphone number: +%s\n", pn);
+}
+
+void
+mbim_printclasses(char *tag, int c)
+{
+       int      i;
+       char    *sep = "";
+
+       printf("\t%s: ", tag);
+       i = 0;
+       while (mbim_dataclass[i].descr) {
+               if (mbim_dataclass[i].val & c) {
+                       printf("%s%s", sep, mbim_dataclass[i].descr);
+                       sep = ",";
+               }
+               i++;
+       }
+       printf("\n");
+}
+
+int
+mbim_parse_classes(const char *spec)
+{
+       char    *optlist, *str;
+       int      c = 0, v;
+
+       if ((optlist = strdup(spec)) == NULL)
+               err(1, "strdup");
+       str = strtok(optlist, ",");
+       while (str != NULL) {
+               if ((v = mbim_descr2val(mbim_dataclass, str)) != 0 ||
+                   (v = mbim_descr2val(mbim_classalias, str)) != 0)
+                       c |= v;
+               str = strtok(NULL, ",");
+       }
+       free(optlist);
+       return c;
+}
+
+void
+mbim_setpin(const char *pin, int d)
+{
+       mbim_pinop(MBIM_PIN_OP_ENTER, 0, pin, NULL);
+}
+
+void
+mbim_chgpin(const char *pin, const char *newpin)
+{
+       mbim_pinop(MBIM_PIN_OP_CHANGE, 0, pin, newpin);
+}
+
+void
+mbim_puk(const char *pin, const char *newpin)
+{
+       mbim_pinop(MBIM_PIN_OP_ENTER, 1, pin, newpin);
+}
+
+void
+mbim_pinop(int op, int is_puk, const char *pin, const char *newpin)
+{
+       struct mbim_parameter mp;
+
+       memset(&mp, 0, sizeof (mp));
+       ifr.ifr_data = (caddr_t)&mp;
+       if (ioctl(s, SIOCGMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCGMBIMPARAM");
+
+       mp.op = op;
+       mp.is_puk = is_puk;
+       if ((mp.pinlen = char_to_utf16(pin, (uint16_t *)mp.pin,
+           sizeof (mp.pin))) == -1)
+               errx(1, "PIN too long");
+
+       if (newpin) {
+               if ((mp.newpinlen = char_to_utf16(newpin, (uint16_t *)mp.newpin,
+                   sizeof (mp.newpin))) == -1)
+               errx(1, "new PIN too long");
+       }
+
+       if (ioctl(s, SIOCSMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCSMBIMPARAM");
+}
+
+void
+mbim_apn(const char *apn, int d)
+{
+       struct mbim_parameter mp;
+
+       memset(&mp, 0, sizeof (mp));
+       ifr.ifr_data = (caddr_t)&mp;
+       if (ioctl(s, SIOCGMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCGMBIMPARAM");
+
+       if (d != 0)
+               memset(mp.apn, 0, sizeof (mp.apn));
+       else if ((mp.apnlen = char_to_utf16(apn, mp.apn,
+           sizeof (mp.apn))) == -1)
+               errx(1, "APN too long");
+
+       if (ioctl(s, SIOCSMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCSMBIMPARAM");
+}
+
+void
+mbim_setclass(const char *val, int d)
+{
+       struct mbim_parameter mp;
+
+       if (val == NULL) {
+               if (showclasses)
+                       usage(1);
+               showclasses = 1;
+               return;
+       }
+
+       memset(&mp, 0, sizeof (mp));
+       ifr.ifr_data = (caddr_t)&mp;
+       if (ioctl(s, SIOCGMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCGMBIMPARAM");
+       if (d != -1)
+               mp.preferredclasses = mbim_parse_classes(val);
+       else
+               mp.preferredclasses = MBIM_DATACLASS_NONE;
+       if (ioctl(s, SIOCSMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCSMBIMPARAM");
+}
+
+void
+mbim_roaming(const char *val, int d)
+{
+       struct mbim_parameter mp;
+
+       memset(&mp, 0, sizeof (mp));
+       ifr.ifr_data = (caddr_t)&mp;
+       if (ioctl(s, SIOCGMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCGMBIMPARAM");
+       mp.roaming = d;
+       if (ioctl(s, SIOCSMBIMPARAM, (caddr_t)&ifr) == -1)
+               err(1, "SIOCSMBIMPARAM");
+}
+
+void
+utf16_to_char(uint16_t *in, int inlen, char *out, size_t outlen)
+{
+       uint16_t c;
+
+       while (outlen > 0) {
+               c = inlen > 0 ? letoh16(*in) : 0;
+               if (c == 0 || --outlen == 0) {
+                       /* always NUL terminate result */
+done:
+                       *out = '\0';
+                       break;
+               }
+               *out++ = isascii(c) ? (char)c : '?';
+               in++;
+               inlen -= sizeof (*in);
+       }
+}
+
+int
+char_to_utf16(const char *in, uint16_t *out, size_t outlen)
+{
+       int      n = 0;
+       uint16_t c;
+
+       for (;;) {
+               c = *in++;
+
+               if (c == '\0') {
+                       /*
+                        * NUL termination is not required, but zero out the
+                        * residual buffer
+                        */
+                       memset(out, 0, outlen);
+                       return n;
+               }
+               if (outlen < sizeof (*out))
+                       return -1;
+
+               *out++ = htole16(c);
+               n += sizeof (*out);
+               outlen -= sizeof (*out);
+       }
+}
+
 #endif
 
 #define SIN(x) ((struct sockaddr_in *) &(x))

Reply via email to