aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/netmisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/netmisc.c')
-rw-r--r--fs/cifs/netmisc.c63
1 files changed, 44 insertions, 19 deletions
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index d35d52889cb5..f97851119e6c 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -61,6 +61,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = {
61 {ERRremcd, -EACCES}, 61 {ERRremcd, -EACCES},
62 {ERRdiffdevice, -EXDEV}, 62 {ERRdiffdevice, -EXDEV},
63 {ERRnofiles, -ENOENT}, 63 {ERRnofiles, -ENOENT},
64 {ERRwriteprot, -EROFS},
64 {ERRbadshare, -ETXTBSY}, 65 {ERRbadshare, -ETXTBSY},
65 {ERRlock, -EACCES}, 66 {ERRlock, -EACCES},
66 {ERRunsup, -EINVAL}, 67 {ERRunsup, -EINVAL},
@@ -139,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
139 * Returns 0 on failure. 140 * Returns 0 on failure.
140 */ 141 */
141static int 142static int
142cifs_inet_pton(const int address_family, const char *cp, void *dst) 143cifs_inet_pton(const int address_family, const char *cp, int len, void *dst)
143{ 144{
144 int ret = 0; 145 int ret = 0;
145 146
146 /* calculate length by finding first slash or NULL */ 147 /* calculate length by finding first slash or NULL */
147 if (address_family == AF_INET) 148 if (address_family == AF_INET)
148 ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); 149 ret = in4_pton(cp, len, dst, '\\', NULL);
149 else if (address_family == AF_INET6) 150 else if (address_family == AF_INET6)
150 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); 151 ret = in6_pton(cp, len, dst , '\\', NULL);
151 152
152 cFYI(DBG2, "address conversion returned %d for %s", ret, cp); 153 cFYI(DBG2, "address conversion returned %d for %*.*s",
154 ret, len, len, cp);
153 if (ret > 0) 155 if (ret > 0)
154 ret = 1; 156 ret = 1;
155 return ret; 157 return ret;
@@ -164,43 +166,66 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
164 * Returns 0 on failure. 166 * Returns 0 on failure.
165 */ 167 */
166int 168int
167cifs_convert_address(char *src, void *dst) 169cifs_convert_address(struct sockaddr *dst, const char *src, int len)
168{ 170{
169 int rc; 171 int rc, alen, slen;
170 char *pct, *endp; 172 const char *pct;
173 char *endp, scope_id[13];
171 struct sockaddr_in *s4 = (struct sockaddr_in *) dst; 174 struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
172 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; 175 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
173 176
174 /* IPv4 address */ 177 /* IPv4 address */
175 if (cifs_inet_pton(AF_INET, src, &s4->sin_addr.s_addr)) { 178 if (cifs_inet_pton(AF_INET, src, len, &s4->sin_addr.s_addr)) {
176 s4->sin_family = AF_INET; 179 s4->sin_family = AF_INET;
177 return 1; 180 return 1;
178 } 181 }
179 182
180 /* temporarily terminate string */ 183 /* attempt to exclude the scope ID from the address part */
181 pct = strchr(src, '%'); 184 pct = memchr(src, '%', len);
182 if (pct) 185 alen = pct ? pct - src : len;
183 *pct = '\0';
184
185 rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
186
187 /* repair temp termination (if any) and make pct point to scopeid */
188 if (pct)
189 *pct++ = '%';
190 186
187 rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
191 if (!rc) 188 if (!rc)
192 return rc; 189 return rc;
193 190
194 s6->sin6_family = AF_INET6; 191 s6->sin6_family = AF_INET6;
195 if (pct) { 192 if (pct) {
193 /* grab the scope ID */
194 slen = len - (alen + 1);
195 if (slen <= 0 || slen > 12)
196 return 0;
197 memcpy(scope_id, pct + 1, slen);
198 scope_id[slen] = '\0';
199
196 s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); 200 s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
197 if (!*pct || *endp) 201 if (endp != scope_id + slen)
198 return 0; 202 return 0;
199 } 203 }
200 204
201 return rc; 205 return rc;
202} 206}
203 207
208int
209cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
210 const unsigned short int port)
211{
212 if (!cifs_convert_address(dst, src, len))
213 return 0;
214
215 switch (dst->sa_family) {
216 case AF_INET:
217 ((struct sockaddr_in *)dst)->sin_port = htons(port);
218 break;
219 case AF_INET6:
220 ((struct sockaddr_in6 *)dst)->sin6_port = htons(port);
221 break;
222 default:
223 return 0;
224 }
225
226 return 1;
227}
228
204/***************************************************************************** 229/*****************************************************************************
205convert a NT status code to a dos class/code 230convert a NT status code to a dos class/code
206 *****************************************************************************/ 231 *****************************************************************************/