input/output character sets. Say Y here for the UTF-8 encoding of
          the Unicode/ISO9646 universal character set.
 
+config NLS_UCS2_UTILS
+       tristate "NLS UCS-2 UTILS"
+       help
+         Set of older UCS-2 conversion utilities and tables used by some
+         filesystems including SMB/CIFS.  This includes upper case conversion
+         tables. This will automatically be selected when the filesystem
+         that uses it is selected.
+
 endif # NLS
 
 obj-$(CONFIG_NLS_MAC_ROMANIAN)  += mac-romanian.o
 obj-$(CONFIG_NLS_MAC_ROMAN)     += mac-roman.o
 obj-$(CONFIG_NLS_MAC_TURKISH)   += mac-turkish.o
+obj-$(CONFIG_NLS_UCS2_UTILS)           += nls_ucs2_utils.o
 
-/* SPDX-License-Identifier: GPL-2.0-or-later */
+// SPDX-License-Identifier: GPL-2.0-or-later
 /*
  *   Some of the source code in this file came from fs/cifs/uniupr.h
  *   Copyright (c) International Business Machines  Corp., 2000,2002
  *
- * uniupr.h - Unicode compressed case ranges
+ *   Some of the source code in this file came from fs/cifs/cifs_unicode.c
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2009
+ *   Modified by Steve French (sfrench@us.ibm.com)
+ *   Modified by Namjae Jeon (linkinjeon@kernel.org)
  *
  */
-#ifndef __KSMBD_UNIUPR_H
-#define __KSMBD_UNIUPR_H
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
+#include "nls_ucs2_utils.h"
+
+MODULE_LICENSE("GPL");
 
-#ifndef UNIUPR_NOUPPER
 /*
  * Latin upper case
  */
-signed char SmbUniUpperTable[512] = {
+signed char NlsUniUpperTable[512] = {
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 000-00f */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 010-01f */
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 020-02f */
        0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, /* 1e0-1ef */
        0, 0, -1, -2, 0, -1, 0, 0, 0, -1, 0, -1, 0, -1, 0, -1,  /* 1f0-1ff */
 };
+EXPORT_SYMBOL_GPL(NlsUniUpperTable);
 
 /* Upper case range - Greek */
 static signed char UniCaseRangeU03a0[47] = {
 /*
  * Upper Case Range
  */
-const struct UniCaseRange SmbUniUpperRange[] = {
+const struct UniCaseRange NlsUniUpperRange[] = {
        {0x03a0, 0x03ce, UniCaseRangeU03a0},
        {0x0430, 0x045f, UniCaseRangeU0430},
        {0x0490, 0x04cc, UniCaseRangeU0490},
        {0xff40, 0xff5a, UniCaseRangeUff40},
        {0}
 };
-#endif
-
-#endif /* __KSMBD_UNIUPR_H */
+EXPORT_SYMBOL_GPL(NlsUniUpperRange);
 
--- /dev/null
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Some of the source code in this file came from fs/cifs/cifs_unicode.c
+ * and then via server/unicode.c
+ * cifs_unicode:  Unicode kernel case support
+ *
+ * Function:
+ *     Convert a unicode character to upper or lower case using
+ *     compressed tables.
+ *
+ *   Copyright (c) International Business Machines  Corp., 2000,2009
+ *
+ *
+ * Notes:
+ *     These APIs are based on the C library functions.  The semantics
+ *     should match the C functions but with expanded size operands.
+ *
+ *     The upper/lower functions are based on a table created by mkupr.
+ *     This is a compressed table of upper and lower case conversion.
+ *
+ */
+#ifndef _NLS_UCS2_UTILS_H
+#define _NLS_UCS2_UTILS_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+#include <linux/nls.h>
+#include <linux/unicode.h>
+
+/*
+ * Windows maps these to the user defined 16 bit Unicode range since they are
+ * reserved symbols (along with \ and /), otherwise illegal to store
+ * in filenames in NTFS
+ */
+#define UNI_ASTERISK    ((__u16)('*' + 0xF000))
+#define UNI_QUESTION    ((__u16)('?' + 0xF000))
+#define UNI_COLON       ((__u16)(':' + 0xF000))
+#define UNI_GRTRTHAN    ((__u16)('>' + 0xF000))
+#define UNI_LESSTHAN    ((__u16)('<' + 0xF000))
+#define UNI_PIPE        ((__u16)('|' + 0xF000))
+#define UNI_SLASH       ((__u16)('\\' + 0xF000))
+
+#ifndef        UNICASERANGE_DEFINED
+struct UniCaseRange {
+       wchar_t start;
+       wchar_t end;
+       signed char *table;
+};
+#endif                         /* UNICASERANGE_DEFINED */
+
+#ifndef UNIUPR_NOUPPER
+extern signed char NlsUniUpperTable[512];
+extern const struct UniCaseRange NlsUniUpperRange[];
+#endif                         /* UNIUPR_NOUPPER */
+
+/*
+ * UniStrcat:  Concatenate the second string to the first
+ *
+ * Returns:
+ *     Address of the first string
+ */
+static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
+{
+       wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
+
+       while (*ucs1++)
+       /*NULL*/;       /* To end of first string */
+       ucs1--;                 /* Return to the null */
+       while ((*ucs1++ = *ucs2++))
+       /*NULL*/;       /* copy string 2 over */
+       return anchor;
+}
+
+/*
+ * UniStrchr:  Find a character in a string
+ *
+ * Returns:
+ *     Address of first occurrence of character in string
+ *     or NULL if the character is not in the string
+ */
+static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
+{
+       while ((*ucs != uc) && *ucs)
+               ucs++;
+
+       if (*ucs == uc)
+               return (wchar_t *)ucs;
+       return NULL;
+}
+
+/*
+ * UniStrcmp:  Compare two strings
+ *
+ * Returns:
+ *     < 0:  First string is less than second
+ *     = 0:  Strings are equal
+ *     > 0:  First string is greater than second
+ */
+static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
+{
+       while ((*ucs1 == *ucs2) && *ucs1) {
+               ucs1++;
+               ucs2++;
+       }
+       return (int)*ucs1 - (int)*ucs2;
+}
+
+/*
+ * UniStrcpy:  Copy a string
+ */
+static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
+{
+       wchar_t *anchor = ucs1; /* save the start of result string */
+
+       while ((*ucs1++ = *ucs2++))
+       /*NULL*/;
+       return anchor;
+}
+
+/*
+ * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
+ */
+static inline size_t UniStrlen(const wchar_t *ucs1)
+{
+       int i = 0;
+
+       while (*ucs1++)
+               i++;
+       return i;
+}
+
+/*
+ * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a
+ *             string (length limited)
+ */
+static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
+{
+       int i = 0;
+
+       while (*ucs1++) {
+               i++;
+               if (i >= maxlen)
+                       break;
+       }
+       return i;
+}
+
+/*
+ * UniStrncat:  Concatenate length limited string
+ */
+static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+       wchar_t *anchor = ucs1; /* save pointer to string 1 */
+
+       while (*ucs1++)
+       /*NULL*/;
+       ucs1--;                 /* point to null terminator of s1 */
+       while (n-- && (*ucs1 = *ucs2)) {        /* copy s2 after s1 */
+               ucs1++;
+               ucs2++;
+       }
+       *ucs1 = 0;              /* Null terminate the result */
+       return anchor;
+}
+
+/*
+ * UniStrncmp:  Compare length limited string
+ */
+static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+       if (!n)
+               return 0;       /* Null strings are equal */
+       while ((*ucs1 == *ucs2) && *ucs1 && --n) {
+               ucs1++;
+               ucs2++;
+       }
+       return (int)*ucs1 - (int)*ucs2;
+}
+
+/*
+ * UniStrncmp_le:  Compare length limited string - native to little-endian
+ */
+static inline int
+UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+       if (!n)
+               return 0;       /* Null strings are equal */
+       while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
+               ucs1++;
+               ucs2++;
+       }
+       return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
+}
+
+/*
+ * UniStrncpy:  Copy length limited string with pad
+ */
+static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+       wchar_t *anchor = ucs1;
+
+       while (n-- && *ucs2)    /* Copy the strings */
+               *ucs1++ = *ucs2++;
+
+       n++;
+       while (n--)             /* Pad with nulls */
+               *ucs1++ = 0;
+       return anchor;
+}
+
+/*
+ * UniStrncpy_le:  Copy length limited string with pad to little-endian
+ */
+static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
+{
+       wchar_t *anchor = ucs1;
+
+       while (n-- && *ucs2)    /* Copy the strings */
+               *ucs1++ = __le16_to_cpu(*ucs2++);
+
+       n++;
+       while (n--)             /* Pad with nulls */
+               *ucs1++ = 0;
+       return anchor;
+}
+
+/*
+ * UniStrstr:  Find a string in a string
+ *
+ * Returns:
+ *     Address of first match found
+ *     NULL if no matching string is found
+ */
+static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
+{
+       const wchar_t *anchor1 = ucs1;
+       const wchar_t *anchor2 = ucs2;
+
+       while (*ucs1) {
+               if (*ucs1 == *ucs2) {
+                       /* Partial match found */
+                       ucs1++;
+                       ucs2++;
+               } else {
+                       if (!*ucs2)     /* Match found */
+                               return (wchar_t *)anchor1;
+                       ucs1 = ++anchor1;       /* No match */
+                       ucs2 = anchor2;
+               }
+       }
+
+       if (!*ucs2)             /* Both end together */
+               return (wchar_t *)anchor1;      /* Match found */
+       return NULL;            /* No match */
+}
+
+#ifndef UNIUPR_NOUPPER
+/*
+ * UniToupper:  Convert a unicode character to upper case
+ */
+static inline wchar_t UniToupper(register wchar_t uc)
+{
+       register const struct UniCaseRange *rp;
+
+       if (uc < sizeof(NlsUniUpperTable)) {
+               /* Latin characters */
+               return uc + NlsUniUpperTable[uc];       /* Use base tables */
+       }
+
+       rp = NlsUniUpperRange;  /* Use range tables */
+       while (rp->start) {
+               if (uc < rp->start)     /* Before start of range */
+                       return uc;      /* Uppercase = input */
+               if (uc <= rp->end)      /* In range */
+                       return uc + rp->table[uc - rp->start];
+               rp++;   /* Try next range */
+       }
+       return uc;              /* Past last range */
+}
+
+/*
+ * UniStrupr:  Upper case a unicode string
+ */
+static inline __le16 *UniStrupr(register __le16 *upin)
+{
+       register __le16 *up;
+
+       up = upin;
+       while (*up) {           /* For all characters */
+               *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
+               up++;
+       }
+       return upin;            /* Return input pointer */
+}
+#endif                         /* UNIUPR_NOUPPER */
+
+#endif /* _NLS_UCS2_UTILS_H */
 
        depends on FILE_LOCKING
        select NLS
        select NLS_UTF8
+       select NLS_UCS2_UTILS
        select CRYPTO
        select CRYPTO_MD5
        select CRYPTO_HMAC
 
 #include <asm/unaligned.h>
 #include "glob.h"
 #include "unicode.h"
-#include "uniupr.h"
 #include "smb_common.h"
 
 /*
 
  *     This is a compressed table of upper and lower case conversion.
  *
  */
-#ifndef _CIFS_UNICODE_H
-#define _CIFS_UNICODE_H
+#ifndef _SMB_UNICODE_H
+#define _SMB_UNICODE_H
 
 #include <asm/byteorder.h>
 #include <linux/types.h>
 #include <linux/nls.h>
 #include <linux/unicode.h>
-
-/*
- * Windows maps these to the user defined 16 bit Unicode range since they are
- * reserved symbols (along with \ and /), otherwise illegal to store
- * in filenames in NTFS
- */
-#define UNI_ASTERISK    ((__u16)('*' + 0xF000))
-#define UNI_QUESTION    ((__u16)('?' + 0xF000))
-#define UNI_COLON       ((__u16)(':' + 0xF000))
-#define UNI_GRTRTHAN    ((__u16)('>' + 0xF000))
-#define UNI_LESSTHAN    ((__u16)('<' + 0xF000))
-#define UNI_PIPE        ((__u16)('|' + 0xF000))
-#define UNI_SLASH       ((__u16)('\\' + 0xF000))
-
-/* Just define what we want from uniupr.h.  We don't want to define the tables
- * in each source file.
- */
-#ifndef        UNICASERANGE_DEFINED
-struct UniCaseRange {
-       wchar_t start;
-       wchar_t end;
-       signed char *table;
-};
-#endif                         /* UNICASERANGE_DEFINED */
-
-#ifndef UNIUPR_NOUPPER
-extern signed char SmbUniUpperTable[512];
-extern const struct UniCaseRange SmbUniUpperRange[];
-#endif                         /* UNIUPR_NOUPPER */
+#include "../../nls/nls_ucs2_utils.h"
 
 #ifdef __KERNEL__
 int smb_strtoUTF16(__le16 *to, const char *from, int len,
 char *ksmbd_extract_sharename(struct unicode_map *um, const char *treename);
 #endif
 
-/*
- * UniStrcat:  Concatenate the second string to the first
- *
- * Returns:
- *     Address of the first string
- */
-static inline wchar_t *UniStrcat(wchar_t *ucs1, const wchar_t *ucs2)
-{
-       wchar_t *anchor = ucs1; /* save a pointer to start of ucs1 */
-
-       while (*ucs1++)
-       /*NULL*/;       /* To end of first string */
-       ucs1--;                 /* Return to the null */
-       while ((*ucs1++ = *ucs2++))
-       /*NULL*/;       /* copy string 2 over */
-       return anchor;
-}
-
-/*
- * UniStrchr:  Find a character in a string
- *
- * Returns:
- *     Address of first occurrence of character in string
- *     or NULL if the character is not in the string
- */
-static inline wchar_t *UniStrchr(const wchar_t *ucs, wchar_t uc)
-{
-       while ((*ucs != uc) && *ucs)
-               ucs++;
-
-       if (*ucs == uc)
-               return (wchar_t *)ucs;
-       return NULL;
-}
-
-/*
- * UniStrcmp:  Compare two strings
- *
- * Returns:
- *     < 0:  First string is less than second
- *     = 0:  Strings are equal
- *     > 0:  First string is greater than second
- */
-static inline int UniStrcmp(const wchar_t *ucs1, const wchar_t *ucs2)
-{
-       while ((*ucs1 == *ucs2) && *ucs1) {
-               ucs1++;
-               ucs2++;
-       }
-       return (int)*ucs1 - (int)*ucs2;
-}
-
-/*
- * UniStrcpy:  Copy a string
- */
-static inline wchar_t *UniStrcpy(wchar_t *ucs1, const wchar_t *ucs2)
-{
-       wchar_t *anchor = ucs1; /* save the start of result string */
-
-       while ((*ucs1++ = *ucs2++))
-       /*NULL*/;
-       return anchor;
-}
-
-/*
- * UniStrlen:  Return the length of a string (in 16 bit Unicode chars not bytes)
- */
-static inline size_t UniStrlen(const wchar_t *ucs1)
-{
-       int i = 0;
-
-       while (*ucs1++)
-               i++;
-       return i;
-}
-
-/*
- * UniStrnlen:  Return the length (in 16 bit Unicode chars not bytes) of a
- *             string (length limited)
- */
-static inline size_t UniStrnlen(const wchar_t *ucs1, int maxlen)
-{
-       int i = 0;
-
-       while (*ucs1++) {
-               i++;
-               if (i >= maxlen)
-                       break;
-       }
-       return i;
-}
-
-/*
- * UniStrncat:  Concatenate length limited string
- */
-static inline wchar_t *UniStrncat(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
-       wchar_t *anchor = ucs1; /* save pointer to string 1 */
-
-       while (*ucs1++)
-       /*NULL*/;
-       ucs1--;                 /* point to null terminator of s1 */
-       while (n-- && (*ucs1 = *ucs2)) {        /* copy s2 after s1 */
-               ucs1++;
-               ucs2++;
-       }
-       *ucs1 = 0;              /* Null terminate the result */
-       return anchor;
-}
-
-/*
- * UniStrncmp:  Compare length limited string
- */
-static inline int UniStrncmp(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
-       if (!n)
-               return 0;       /* Null strings are equal */
-       while ((*ucs1 == *ucs2) && *ucs1 && --n) {
-               ucs1++;
-               ucs2++;
-       }
-       return (int)*ucs1 - (int)*ucs2;
-}
-
-/*
- * UniStrncmp_le:  Compare length limited string - native to little-endian
- */
-static inline int
-UniStrncmp_le(const wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
-       if (!n)
-               return 0;       /* Null strings are equal */
-       while ((*ucs1 == __le16_to_cpu(*ucs2)) && *ucs1 && --n) {
-               ucs1++;
-               ucs2++;
-       }
-       return (int)*ucs1 - (int)__le16_to_cpu(*ucs2);
-}
-
-/*
- * UniStrncpy:  Copy length limited string with pad
- */
-static inline wchar_t *UniStrncpy(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
-       wchar_t *anchor = ucs1;
-
-       while (n-- && *ucs2)    /* Copy the strings */
-               *ucs1++ = *ucs2++;
-
-       n++;
-       while (n--)             /* Pad with nulls */
-               *ucs1++ = 0;
-       return anchor;
-}
-
-/*
- * UniStrncpy_le:  Copy length limited string with pad to little-endian
- */
-static inline wchar_t *UniStrncpy_le(wchar_t *ucs1, const wchar_t *ucs2, size_t n)
-{
-       wchar_t *anchor = ucs1;
-
-       while (n-- && *ucs2)    /* Copy the strings */
-               *ucs1++ = __le16_to_cpu(*ucs2++);
-
-       n++;
-       while (n--)             /* Pad with nulls */
-               *ucs1++ = 0;
-       return anchor;
-}
-
-/*
- * UniStrstr:  Find a string in a string
- *
- * Returns:
- *     Address of first match found
- *     NULL if no matching string is found
- */
-static inline wchar_t *UniStrstr(const wchar_t *ucs1, const wchar_t *ucs2)
-{
-       const wchar_t *anchor1 = ucs1;
-       const wchar_t *anchor2 = ucs2;
-
-       while (*ucs1) {
-               if (*ucs1 == *ucs2) {
-                       /* Partial match found */
-                       ucs1++;
-                       ucs2++;
-               } else {
-                       if (!*ucs2)     /* Match found */
-                               return (wchar_t *)anchor1;
-                       ucs1 = ++anchor1;       /* No match */
-                       ucs2 = anchor2;
-               }
-       }
-
-       if (!*ucs2)             /* Both end together */
-               return (wchar_t *)anchor1;      /* Match found */
-       return NULL;            /* No match */
-}
-
-#ifndef UNIUPR_NOUPPER
-/*
- * UniToupper:  Convert a unicode character to upper case
- */
-static inline wchar_t UniToupper(register wchar_t uc)
-{
-       register const struct UniCaseRange *rp;
-
-       if (uc < sizeof(SmbUniUpperTable)) {
-               /* Latin characters */
-               return uc + SmbUniUpperTable[uc];       /* Use base tables */
-       }
-
-       rp = SmbUniUpperRange;  /* Use range tables */
-       while (rp->start) {
-               if (uc < rp->start)     /* Before start of range */
-                       return uc;      /* Uppercase = input */
-               if (uc <= rp->end)      /* In range */
-                       return uc + rp->table[uc - rp->start];
-               rp++;   /* Try next range */
-       }
-       return uc;              /* Past last range */
-}
-
-/*
- * UniStrupr:  Upper case a unicode string
- */
-static inline __le16 *UniStrupr(register __le16 *upin)
-{
-       register __le16 *up;
-
-       up = upin;
-       while (*up) {           /* For all characters */
-               *up = cpu_to_le16(UniToupper(le16_to_cpu(*up)));
-               up++;
-       }
-       return upin;            /* Return input pointer */
-}
-#endif                         /* UNIUPR_NOUPPER */
-
-#endif /* _CIFS_UNICODE_H */
+#endif /* _SMB_UNICODE_H */