The branch main has been updated by adrian:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=0f1bf1c22a0c97e84a4db19197a75952487aa20b

commit 0f1bf1c22a0c97e84a4db19197a75952487aa20b
Author:     Adrian Chadd <[email protected]>
AuthorDate: 2025-01-20 23:46:15 +0000
Commit:     Adrian Chadd <[email protected]>
CommitDate: 2025-01-20 23:46:15 +0000

    umb: Introduce the USB umb(4) network driver
    
    This includes the port of a driver originally from OpenBSD, later
    ported to NetBSD by the author:
    
    * The umb(4) kernel driver
    * The umbctl(8) companion tool
    
    This driver supports USB network devices implementing the
    Mobile Broadband Interface Model (MBIM), often found in modern
    (internal) USB models for 4G/LTE mobile broadband access.
    
    It is currently limited to IPv4.
    
    umbctl has to be used to display or set MBIM cellular modem
    interface parameters (4G/LTE).
    
    Differential Revision:  https://reviews.freebsd.org/D48167
    Approved by:    adrian, zlei
    Sponsored by:   FreeBSD Foundation
    PR:             kern/263783
    Submitted by:   Pierre Pronchery <[email protected]>
---
 sbin/Makefile                |    1 +
 sbin/umbctl/Makefile         |    8 +
 sbin/umbctl/umbctl.8         |  161 +++
 sbin/umbctl/umbctl.c         |  557 ++++++++
 share/man/man4/Makefile      |    1 +
 share/man/man4/umb.4         |  119 ++
 sys/conf/files               |    1 +
 sys/dev/usb/net/if_umb.c     | 2930 ++++++++++++++++++++++++++++++++++++++++++
 sys/dev/usb/net/if_umbreg.h  |  443 +++++++
 sys/dev/usb/net/mbim.h       |  727 +++++++++++
 sys/modules/usb/Makefile     |    2 +-
 sys/modules/usb/umb/Makefile |   33 +
 12 files changed, 4982 insertions(+), 1 deletion(-)

diff --git a/sbin/Makefile b/sbin/Makefile
index 790112b05f6f..5e5a8943c67a 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -63,6 +63,7 @@ SUBDIR=adjkerntz \
        swapon \
        sysctl \
        tunefs \
+       umbctl \
        umount
 
 .if ${MK_INET} != "no" || ${MK_INET6} != "no"
diff --git a/sbin/umbctl/Makefile b/sbin/umbctl/Makefile
new file mode 100644
index 000000000000..35afb1bcfd4b
--- /dev/null
+++ b/sbin/umbctl/Makefile
@@ -0,0 +1,8 @@
+CFLAGS+= -I${SRCTOP}/sys/dev/usb/net
+
+PROG=  umbctl
+MAN=   umbctl.8
+
+BINDIR=        /sbin
+
+.include <bsd.prog.mk>
diff --git a/sbin/umbctl/umbctl.8 b/sbin/umbctl/umbctl.8
new file mode 100644
index 000000000000..55f8e315fabc
--- /dev/null
+++ b/sbin/umbctl/umbctl.8
@@ -0,0 +1,161 @@
+.\"-
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2018 by Pierre Pronchery <[email protected]>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
+.\" OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" From: pppoectl.8,v 1.30 2016/09/12 05:35:20 sevan Exp $
+.\"
+.\" $NetBSD: umbctl.8,v 1.3 2020/03/22 07:45:02 khorben Exp $
+.\"
+.\" last edit-date: [Fri Dec 20 18:20:00 2024]
+.\"
+.Dd December 20, 2024
+.Dt UMBCTL 8
+.Os
+.Sh NAME
+.Nm umbctl
+.Nd display or set MBIM cellular modem interface parameters (4G/LTE)
+.Sh SYNOPSIS
+.Nm
+.Op Fl v
+.Ar ifname
+.Op Ar parameter Op Ar value
+.Ar ...
+.Nm
+.Op Fl v
+.Fl f Ar config-file
+.Ar ifname
+.Sh DESCRIPTION
+.Nm
+supports the following options:
+.Bl -tag -width "-f config_file"
+.It Fl f Ar config-file
+Parse
+.Ar config-file
+for
+.Ar parameter Ns Op \&= Ns Ar value
+pairs, one per line, as if they had been specified on the command line.
+This allows the password or PIN codes to be not passed as command line
+arguments.
+Comments starting with # to the end of the current line are ignored.
+.It Fl v
+Enables verbose mode.
+.El
+.Pp
+The
+.Xr umb 4
+driver may require a number of additional arguments or optional
+parameters besides the settings that can be adjusted with
+.Xr ifconfig 8 .
+These may be credentials or other tunable connectivity variables.
+The
+.Nm
+utility can be used to display the current settings, or to adjust these
+parameters as required.
+.Pp
+For whatever intent
+.Nm
+is being called, at least the parameter
+.Ar ifname
+needs to be specified, naming the interface for which the settings
+are to be performed or displayed.
+Use
+.Xr ifconfig 8
+or
+.Xr netstat 1
+to see which interfaces are available.
+.Pp
+If no other parameter is given,
+.Nm
+will just list the current status for
+.Ar ifname
+and exit.
+.Pp
+If any additional parameter is supplied, superuser privileges are
+required, and the command works in
+.Ql set
+mode.
+This is normally done quietly, unless the option
+.Fl v
+is also enabled, which will cause a final printout of the status as
+described above once all other actions have been taken.
+.Pp
+The parameters currently supported include:
+.Bl -tag -width "username=username"
+.It Ar apn Ns \&= Ns Em access-point
+Set the APN to
+.Em access-point .
+.It Ar username Ns \&= Ns Em username
+Set the username to
+.Em username .
+.It Ar password Ns \&= Ns Em password
+Set the password to
+.Em password .
+.It Ar pin Ns \&= Ns Em pin-code
+Enter the PIN
+.Em pin-code .
+.It Ar puk Ns \&= Ns Em puk-code
+Enter the PUK
+.Em puk-code .
+.It Ar roaming
+Allow data connections when roaming.
+.It Ar -roaming
+Deny data connections when roaming.
+.El
+.Sh EXAMPLES
+Display the settings for umb0:
+.Bd -literal
+# umbctl umb0
+umb0: state up, mode automatic, registration home network
+       provider "BSD-Net", dataclass LTE, signal good
+       phone number "+15554242", roaming "" (denied)
+       APN "", TX 50000000, RX 100000000
+       firmware "MBIM_FW_V1.0", hardware "MBIM_HW_V1.0"
+.Ed
+.Pp
+Configure the connection parameters for umb0 from the command line:
+.Bd -literal
+# umbctl umb0 apn operator.internet username mobile password mobile
+.Ed
+.Pp
+Configure the connection parameters for umb0 from a file:
+.Bd -literal
+# umbctl -f /dev/stdin umb0 << EOF
+pin=1234
+EOF
+.Ed
+.Sh SEE ALSO
+.Xr netstat 1 ,
+.Xr umb 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Nx 9.0 ,
+and
+.Fx 15.0 .
+.Sh AUTHORS
+The program was written by
+.An Pierre Pronchery .
diff --git a/sbin/umbctl/umbctl.c b/sbin/umbctl/umbctl.c
new file mode 100644
index 000000000000..3d57b486ad80
--- /dev/null
+++ b/sbin/umbctl/umbctl.c
@@ -0,0 +1,557 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Original copyright (c) 2018 Pierre Pronchery <[email protected]> (for the
+ * NetBSD Project)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Copyright (c) 2022 ADISTA SAS (FreeBSD updates)
+ *
+ * Updates for FreeBSD by Pierre Pronchery <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * - Neither the name of the copyright holder nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $NetBSD: umbctl.c,v 1.4 2020/05/13 21:44:30 khorben Exp $
+ */
+
+#include <sys/endian.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "mbim.h"
+#include "if_umbreg.h"
+
+/* constants */
+static const struct umb_valdescr _umb_actstate[] =
+       MBIM_ACTIVATION_STATE_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_simstate[] =
+       MBIM_SIMSTATE_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_regstate[] =
+       MBIM_REGSTATE_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_pktstate[] =
+       MBIM_PKTSRV_STATE_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_dataclass[] =
+       MBIM_DATACLASS_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_state[] =
+       UMB_INTERNAL_STATE_DESCRIPTIONS;
+
+static const struct umb_valdescr _umb_pin_state[] =
+{
+       { UMB_PIN_REQUIRED, "PIN required"},
+       { UMB_PIN_UNLOCKED, "PIN unlocked"},
+       { UMB_PUK_REQUIRED, "PUK required"},
+       { 0, NULL }
+};
+
+static const struct umb_valdescr _umb_regmode[] =
+{
+       { MBIM_REGMODE_UNKNOWN, "unknown" },
+       { MBIM_REGMODE_AUTOMATIC, "automatic" },
+       { MBIM_REGMODE_MANUAL, "manual" },
+       { 0, NULL }
+};
+
+static const struct umb_valdescr _umb_ber[] =
+{
+       { UMB_BER_EXCELLENT, "excellent" },
+       { UMB_BER_VERYGOOD, "very good" },
+       { UMB_BER_GOOD, "good" },
+       { UMB_BER_OK, "ok" },
+       { UMB_BER_MEDIUM, "medium" },
+       { UMB_BER_BAD, "bad" },
+       { UMB_BER_VERYBAD, "very bad" },
+       { UMB_BER_EXTREMELYBAD, "extremely bad" },
+       { 0, NULL }
+};
+
+
+/* prototypes */
+static int _char_to_utf16(const char * in, uint16_t * out, size_t outlen);
+static int _error(int ret, char const * format, ...);
+static int _umbctl(char const * ifname, int verbose, int argc, char * argv[]);
+static int _umbctl_file(char const * ifname, char const * filename,
+               int verbose);
+static void _umbctl_info(char const * ifname, struct umb_info * umbi);
+static int _umbctl_ioctl(char const * ifname, int fd, unsigned long request,
+               struct ifreq * ifr);
+static int _umbctl_set(char const * ifname, struct umb_parameter * umbp,
+               int argc, char * argv[]);
+static int _umbctl_socket(void);
+static int _usage(void);
+static void _utf16_to_char(uint16_t * in, int inlen, char * out, size_t 
outlen);
+
+
+/* functions */
+/* char_to_utf16 */
+/* this function is from OpenBSD's ifconfig(8) */
+static 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);
+       }
+}
+
+
+/* error */
+static int _error(int ret, char const * format, ...)
+{
+       va_list ap;
+
+       fputs("umbctl: ", stderr);
+       va_start(ap, format);
+       vfprintf(stderr, format, ap);
+       va_end(ap);
+       fputs("\n", stderr);
+       return ret;
+}
+
+
+/* umbctl */
+static int _umbctl(char const * ifname, int verbose, int argc, char * argv[])
+{
+       int fd;
+       struct ifreq ifr;
+       struct umb_info umbi;
+       struct umb_parameter umbp;
+
+       if((fd = _umbctl_socket()) < 0)
+               return 2;
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+       if(argc != 0)
+       {
+               memset(&umbp, 0, sizeof(umbp));
+               ifr.ifr_data = (caddr_t)&umbp;
+               if(_umbctl_ioctl(ifname, fd, SIOCGUMBPARAM, &ifr) != 0
+                               || _umbctl_set(ifname, &umbp, argc, argv) != 0
+                               || _umbctl_ioctl(ifname, fd, SIOCSUMBPARAM,
+                                       &ifr) != 0)
+               {
+                       close(fd);
+                       return 2;
+               }
+       }
+       if(argc == 0 || verbose > 0)
+       {
+               ifr.ifr_data = (caddr_t)&umbi;
+               if(_umbctl_ioctl(ifname, fd, SIOCGUMBINFO, &ifr) != 0)
+               {
+                       close(fd);
+                       return 3;
+               }
+               _umbctl_info(ifname, &umbi);
+       }
+       if(close(fd) != 0)
+               return _error(2, "%s: %s", ifname, strerror(errno));
+       return 0;
+}
+
+
+/* umbctl_file */
+static int _file_parse(char const * ifname, struct umb_parameter * umbp,
+               char const * filename);
+
+static int _umbctl_file(char const * ifname, char const * filename, int 
verbose)
+{
+       int fd;
+       struct ifreq ifr;
+       struct umb_parameter umbp;
+       struct umb_info umbi;
+
+       if((fd = _umbctl_socket()) < 0)
+               return 2;
+       memset(&ifr, 0, sizeof(ifr));
+       strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+       ifr.ifr_data = (caddr_t)&umbp;
+       memset(&umbp, 0, sizeof(umbp));
+       if(_umbctl_ioctl(ifname, fd, SIOCGUMBPARAM, &ifr) != 0
+                       || _file_parse(ifname, &umbp, filename) != 0
+                       || _umbctl_ioctl(ifname, fd, SIOCSUMBPARAM, &ifr) != 0)
+       {
+               close(fd);
+               return 2;
+       }
+       if(verbose > 0)
+       {
+               ifr.ifr_data = (caddr_t)&umbi;
+               if(_umbctl_ioctl(ifname, fd, SIOCGUMBINFO, &ifr) != 0)
+               {
+                       close(fd);
+                       return 3;
+               }
+               _umbctl_info(ifname, &umbi);
+       }
+       if(close(fd) != 0)
+               return _error(2, "%s: %s", ifname, strerror(errno));
+       return 0;
+}
+
+static int _file_parse(char const * ifname, struct umb_parameter * umbp,
+               char const * filename)
+{
+       int ret = 0;
+       FILE * fp;
+       char buf[512];
+       size_t len;
+       int i;
+       int eof;
+       char * tokens[3] = { buf, NULL, NULL };
+       char * p;
+
+       if((fp = fopen(filename, "r")) == NULL)
+               return _error(2, "%s: %s", filename, strerror(errno));
+       while(fgets(buf, sizeof(buf), fp) != NULL)
+       {
+               if(buf[0] == '#')
+                       continue;
+               buf[sizeof(buf) - 1] = '\0';
+               if((len = strlen(buf)) > 0)
+               {
+                       if(buf[len - 1] != '\n')
+                       {
+                               ret = _error(2, "%s: %s", filename,
+                                               "Line too long");
+                               while((i = fgetc(fp)) != EOF && i != '\n');
+                               continue;
+                       }
+                       buf[len - 1] = '\0';
+               }
+               if((p = strchr(buf, '=')) != NULL)
+               {
+                       tokens[1] = p + 1;
+                       *p = '\0';
+               } else
+                       tokens[1] = NULL;
+               ret |= _umbctl_set(ifname, umbp, (p != NULL) ? 2 : 1, tokens)
+                       ? 2 : 0;
+       }
+       eof = feof(fp);
+       if(fclose(fp) != 0 || !eof)
+               return _error(2, "%s: %s", filename, strerror(errno));
+       return ret;
+}
+
+
+/* umbctl_info */
+static void _umbctl_info(char const * ifname, struct umb_info * umbi)
+{
+       char provider[UMB_PROVIDERNAME_MAXLEN + 1];
+       char pn[UMB_PHONENR_MAXLEN + 1];
+       char roaming[UMB_ROAMINGTEXT_MAXLEN + 1];
+       char apn[UMB_APN_MAXLEN + 1];
+       char fwinfo[UMB_FWINFO_MAXLEN + 1];
+       char hwinfo[UMB_HWINFO_MAXLEN + 1];
+
+       _utf16_to_char(umbi->provider, UMB_PROVIDERNAME_MAXLEN,
+                       provider, sizeof(provider));
+       _utf16_to_char(umbi->pn, UMB_PHONENR_MAXLEN, pn, sizeof(pn));
+       _utf16_to_char(umbi->roamingtxt, UMB_ROAMINGTEXT_MAXLEN,
+                       roaming, sizeof(roaming));
+       _utf16_to_char(umbi->apn, UMB_APN_MAXLEN, apn, sizeof(apn));
+       _utf16_to_char(umbi->fwinfo, UMB_FWINFO_MAXLEN, fwinfo, sizeof(fwinfo));
+       _utf16_to_char(umbi->hwinfo, UMB_HWINFO_MAXLEN, hwinfo, sizeof(hwinfo));
+       printf("%s: state %s, mode %s, registration %s\n"
+                       "\tprovider \"%s\", dataclass %s, signal %s\n"
+                       "\tphone number \"%s\", roaming \"%s\" (%s)\n"
+                       "\tAPN \"%s\", TX %" PRIu64 ", RX %" PRIu64 "\n"
+                       "\tfirmware \"%s\", hardware \"%s\"\n",
+                       ifname, umb_val2descr(_umb_state, umbi->state),
+                       umb_val2descr(_umb_regmode, umbi->regmode),
+                       umb_val2descr(_umb_regstate, umbi->regstate), provider,
+                       umb_val2descr(_umb_dataclass, umbi->cellclass),
+                       umb_val2descr(_umb_ber, umbi->ber), pn, roaming,
+                       umbi->enable_roaming ? "allowed" : "denied",
+                       apn, umbi->uplink_speed, umbi->downlink_speed,
+                       fwinfo, hwinfo);
+}
+
+
+/* umbctl_ioctl */
+static int _umbctl_ioctl(char const * ifname, int fd, unsigned long request,
+               struct ifreq * ifr)
+{
+       if(ioctl(fd, request, ifr) != 0)
+               return _error(-1, "%s: %s", ifname, strerror(errno));
+       return 0;
+}
+
+
+/* umbctl_set */
+/* callbacks */
+static int _set_apn(char const *, struct umb_parameter *, char const *);
+static int _set_username(char const *, struct umb_parameter *, char const *);
+static int _set_password(char const *, struct umb_parameter *, char const *);
+static int _set_pin(char const *, struct umb_parameter *, char const *);
+static int _set_puk(char const *, struct umb_parameter *, char const *);
+static int _set_roaming_allow(char const *, struct umb_parameter *,
+               char const *);
+static int _set_roaming_deny(char const *, struct umb_parameter *,
+               char const *);
+
+static int _umbctl_set(char const * ifname, struct umb_parameter * umbp,
+               int argc, char * argv[])
+{
+       struct
+       {
+               char const * name;
+               int (*callback)(char const *,
+                               struct umb_parameter *, char const *);
+               int parameter;
+       } callbacks[] =
+       {
+               { "apn", _set_apn, 1 },
+               { "username", _set_username, 1 },
+               { "password", _set_password, 1 },
+               { "pin", _set_pin, 1 },
+               { "puk", _set_puk, 1 },
+               { "roaming", _set_roaming_allow, 0 },
+               { "-roaming", _set_roaming_deny, 0 },
+       };
+       int i;
+       size_t j;
+
+       for(i = 0; i < argc; i++)
+       {
+               for(j = 0; j < sizeof(callbacks) / sizeof(*callbacks); j++)
+                       if(strcmp(argv[i], callbacks[j].name) == 0)
+                       {
+                               if(callbacks[j].parameter && i + 1 == argc)
+                                       return _error(-1, "%s: Incomplete"
+                                                       " parameter", argv[i]);
+                               if(callbacks[j].callback(ifname, umbp,
+                                                       callbacks[j].parameter
+                                                       ? argv[i + 1] : NULL))
+                                       return -1;
+                               if(callbacks[j].parameter)
+                                       i++;
+                               break;
+                       }
+               if(j == sizeof(callbacks) / sizeof(*callbacks))
+                       return _error(-1, "%s: Unknown parameter", argv[i]);
+       }
+       return 0;
+}
+
+static int _set_apn(char const * ifname, struct umb_parameter * umbp,
+               char const * apn)
+{
+       umbp->apnlen = _char_to_utf16(apn, umbp->apn, sizeof(umbp->apn));
+       if(umbp->apnlen < 0 || (size_t)umbp->apnlen > sizeof(umbp->apn))
+               return _error(-1, "%s: %s", ifname, "APN too long");
+       return 0;
+}
+
+static int _set_username(char const * ifname, struct umb_parameter * umbp,
+               char const * username)
+{
+       umbp->usernamelen = _char_to_utf16(username, umbp->username,
+                       sizeof(umbp->username));
+       if(umbp->usernamelen < 0
+                       || (size_t)umbp->usernamelen > sizeof(umbp->username))
+               return _error(-1, "%s: %s", ifname, "Username too long");
+       return 0;
+}
+
+static int _set_password(char const * ifname, struct umb_parameter * umbp,
+               char const * password)
+{
+       umbp->passwordlen = _char_to_utf16(password, umbp->password,
+                       sizeof(umbp->password));
+       if(umbp->passwordlen < 0
+                       || (size_t)umbp->passwordlen > sizeof(umbp->password))
+               return _error(-1, "%s: %s", ifname, "Password too long");
+       return 0;
+}
+
+static int _set_pin(char const * ifname, struct umb_parameter * umbp,
+               char const * pin)
+{
+       umbp->is_puk = 0;
+       umbp->op = MBIM_PIN_OP_ENTER;
+       umbp->pinlen = _char_to_utf16(pin, umbp->pin, sizeof(umbp->pin));
+       if(umbp->pinlen < 0 || (size_t)umbp->pinlen
+                       > sizeof(umbp->pin))
+               return _error(-1, "%s: %s", ifname, "PIN code too long");
+       return 0;
+}
+
+static int _set_puk(char const * ifname, struct umb_parameter * umbp,
+               char const * puk)
+{
+       umbp->is_puk = 1;
+       umbp->op = MBIM_PIN_OP_ENTER;
+       umbp->pinlen = _char_to_utf16(puk, umbp->pin, sizeof(umbp->pin));
+       if(umbp->pinlen < 0 || (size_t)umbp->pinlen > sizeof(umbp->pin))
+               return _error(-1, "%s: %s", ifname, "PUK code too long");
+       return 0;
+}
+
+static int _set_roaming_allow(char const * ifname, struct umb_parameter * umbp,
+               char const * unused)
+{
+       (void) ifname;
+       (void) unused;
+
+       umbp->roaming = 1;
+       return 0;
+}
+
+static int _set_roaming_deny(char const * ifname, struct umb_parameter * umbp,
+               char const * unused)
+{
+       (void) ifname;
+       (void) unused;
+
+       umbp->roaming = 0;
+       return 0;
+}
+
+
+/* umbctl_socket */
+static int _umbctl_socket(void)
+{
+       int fd;
+
+       if((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+               return _error(-1, "socket: %s", strerror(errno));
+       return fd;
+}
+
+
+/* usage */
+static int _usage(void)
+{
+       fputs("Usage: umbctl [-v] ifname [parameter [value]] [...]\n"
+"       umbctl -f config-file ifname\n",
+                       stderr);
+       return 1;
+}
+
+
+/* utf16_to_char */
+static void _utf16_to_char(uint16_t * in, int inlen, char * out, size_t outlen)
+{
+       uint16_t c;
+
+       while (outlen > 0) {
+               c = inlen > 0 ? htole16(*in) : 0;
+               if (c == 0 || --outlen == 0) {
+                       /* always NUL terminate result */
+                       *out = '\0';
+                       break;
+               }
+               *out++ = isascii(c) ? (char)c : '?';
+               in++;
+               inlen--;
+       }
+}
+
+
+/* main */
+int main(int argc, char * argv[])
+{
+       int o;
+       char const * filename = NULL;
+       int verbose = 0;
+
+       while((o = getopt(argc, argv, "f:gv")) != -1)
+               switch(o)
+               {
+                       case 'f':
+                               filename = optarg;
+                               break;
+                       case 'v':
+                               verbose++;
+                               break;
+                       default:
+                               return _usage();
+               }
+       if(optind == argc)
+               return _usage();
+       if(filename != NULL)
+       {
+               if(optind + 1 != argc)
+                       return _usage();
+               return _umbctl_file(argv[optind], filename, verbose);
+       }
+       return _umbctl(argv[optind], verbose, argc - optind - 1,
+                       &argv[optind + 1]);
+}
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index c03ba63c349f..9dc1c7f9bc12 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1041,6 +1041,7 @@ MAN+=     \
        uled.4 \
        ulpt.4 \
        umass.4 \
+       umb.4 \
        umcs.4 \
        umct.4 \
        umodem.4 \
diff --git a/share/man/man4/umb.4 b/share/man/man4/umb.4
new file mode 100644
index 000000000000..b0d517095933
--- /dev/null
+++ b/share/man/man4/umb.4
@@ -0,0 +1,119 @@
+.\"-
+.\" SPDX-License-Identifier: 0BSD
+.\"
+.\" Copyright (c) 2016 genua mbH
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $NetBSD: umb.4,v 1.4 2019/08/30 09:22:17 wiz Exp $
+.\"
+.Dd August 24, 2019
+.Dt UMB 4
+.Os
+.Sh NAME
+.Nm umb
+.Nd USB Mobile Broadband Interface Model (MBIM)
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device usb"
+.Cd "device umb"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+umb_load="YES"
+.Ed
+.Pp
+If neither of the above is done, the driver will automatically be loaded
+by devd(8) when the device is connected.
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for USB MBIM devices.
+.Pp
+MBIM devices establish connections via cellular networks such as
+GPRS, UMTS, and LTE.
+They appear as a regular point-to-point network interface,
+transporting raw IP frames.
+.Pp
+Required configuration parameters like PIN and APN have to be set
+with
+.Xr umbctl 8 .
+Once the SIM card has been unlocked with the correct PIN, it
+will remain in this state until the MBIM device is power-cycled.
+In case the device is connected to an "always-on" USB port,
+it may be possible to connect to a provider without entering the
+PIN again even if the system was rebooted.
+.Sh HARDWARE
+The
+.Nm
+driver should support any USB device implementing MBIM, including
+the following cellular modems:
+.Pp
+.Bl -bullet -compact
+.It
+Ericsson H5321gw and N5321gw
+.It
+Fibocom L831-EAU
+.It
+Medion Mobile S4222 (MediaTek OEM)
+.It
+Sierra Wireless EM7345
+.It
+Sierra Wireless EM7455
+.It
+Sierra Wireless EM8805
+.It
+Sierra Wireless MC8305
+.El
+.Sh SEE ALSO
+.Xr intro 4 ,
+.Xr netintro 4 ,
+.Xr usb 4 ,
+.Xr ifconfig 8 ,
+.Xr umbctl 8
+.Rs
+.%T "Universal Serial Bus Communications Class Subclass Specification for 
Mobile Broadband Interface Model"
+.%U http://www.usb.org/developers/docs/devclass_docs/MBIM10Errata1_073013.zip
+.Re
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Ox 6.0 ,
+.Nx 9.0 ,
+and
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Gerhard Roth Aq Mt [email protected]
+and ported from
+.Ox
+by
+.An Pierre Pronchery Aq Mt [email protected] .
+.Sh CAVEATS
+The
+.Nm
+driver does not support IPv6.
+.Pp
+Devices which fail to provide a conforming MBIM implementation will
+probably be attached as some other driver, such as
+.Xr u3g 4 .
diff --git a/sys/conf/files b/sys/conf/files
index a02174f3d954..5fd7b887581a 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3293,6 +3293,7 @@ dev/usb/net/if_muge.c             optional muge
 dev/usb/net/if_rue.c           optional rue
 dev/usb/net/if_smsc.c          optional smsc
 dev/usb/net/if_udav.c          optional udav
+dev/usb/net/if_umb.c           optional umb
 dev/usb/net/if_ure.c           optional ure
 dev/usb/net/if_usie.c          optional usie
 dev/usb/net/if_urndis.c                optional urndis
diff --git a/sys/dev/usb/net/if_umb.c b/sys/dev/usb/net/if_umb.c
new file mode 100644
index 000000000000..9b2b504cfa6b
--- /dev/null
+++ b/sys/dev/usb/net/if_umb.c
@@ -0,0 +1,2930 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Original copyright (c) 2016 genua mbH (OpenBSD version)
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Copyright (c) 2022 ADISTA SAS (re-write for FreeBSD)
+ *
+ * Re-write for FreeBSD by Pierre Pronchery <[email protected]>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright notice,
+ *   this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
*** 4136 LINES SKIPPED ***

Reply via email to