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.c45
1 files changed, 24 insertions, 21 deletions
diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c
index c6721ee26dbc..f97851119e6c 100644
--- a/fs/cifs/netmisc.c
+++ b/fs/cifs/netmisc.c
@@ -140,17 +140,18 @@ static const struct smb_to_posix_error mapping_table_ERRHRD[] = {
140 * Returns 0 on failure. 140 * Returns 0 on failure.
141 */ 141 */
142static int 142static int
143cifs_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)
144{ 144{
145 int ret = 0; 145 int ret = 0;
146 146
147 /* calculate length by finding first slash or NULL */ 147 /* calculate length by finding first slash or NULL */
148 if (address_family == AF_INET) 148 if (address_family == AF_INET)
149 ret = in4_pton(cp, -1 /* len */, dst, '\\', NULL); 149 ret = in4_pton(cp, len, dst, '\\', NULL);
150 else if (address_family == AF_INET6) 150 else if (address_family == AF_INET6)
151 ret = in6_pton(cp, -1 /* len */, dst , '\\', NULL); 151 ret = in6_pton(cp, len, dst , '\\', NULL);
152 152
153 cFYI(DBG2, "address conversion returned %d for %s", ret, cp); 153 cFYI(DBG2, "address conversion returned %d for %*.*s",
154 ret, len, len, cp);
154 if (ret > 0) 155 if (ret > 0)
155 ret = 1; 156 ret = 1;
156 return ret; 157 return ret;
@@ -165,37 +166,39 @@ cifs_inet_pton(const int address_family, const char *cp, void *dst)
165 * Returns 0 on failure. 166 * Returns 0 on failure.
166 */ 167 */
167int 168int
168cifs_convert_address(struct sockaddr *dst, char *src) 169cifs_convert_address(struct sockaddr *dst, const char *src, int len)
169{ 170{
170 int rc; 171 int rc, alen, slen;
171 char *pct, *endp; 172 const char *pct;
173 char *endp, scope_id[13];
172 struct sockaddr_in *s4 = (struct sockaddr_in *) dst; 174 struct sockaddr_in *s4 = (struct sockaddr_in *) dst;
173 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst; 175 struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) dst;
174 176
175 /* IPv4 address */ 177 /* IPv4 address */
176 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)) {
177 s4->sin_family = AF_INET; 179 s4->sin_family = AF_INET;
178 return 1; 180 return 1;
179 } 181 }
180 182
181 /* temporarily terminate string */ 183 /* attempt to exclude the scope ID from the address part */
182 pct = strchr(src, '%'); 184 pct = memchr(src, '%', len);
183 if (pct) 185 alen = pct ? pct - src : len;
184 *pct = '\0';
185
186 rc = cifs_inet_pton(AF_INET6, src, &s6->sin6_addr.s6_addr);
187
188 /* repair temp termination (if any) and make pct point to scopeid */
189 if (pct)
190 *pct++ = '%';
191 186
187 rc = cifs_inet_pton(AF_INET6, src, alen, &s6->sin6_addr.s6_addr);
192 if (!rc) 188 if (!rc)
193 return rc; 189 return rc;
194 190
195 s6->sin6_family = AF_INET6; 191 s6->sin6_family = AF_INET6;
196 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
197 s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0); 200 s6->sin6_scope_id = (u32) simple_strtoul(pct, &endp, 0);
198 if (!*pct || *endp) 201 if (endp != scope_id + slen)
199 return 0; 202 return 0;
200 } 203 }
201 204
@@ -203,10 +206,10 @@ cifs_convert_address(struct sockaddr *dst, char *src)
203} 206}
204 207
205int 208int
206cifs_fill_sockaddr(struct sockaddr *dst, char *src, 209cifs_fill_sockaddr(struct sockaddr *dst, const char *src, int len,
207 const unsigned short int port) 210 const unsigned short int port)
208{ 211{
209 if (!cifs_convert_address(dst, src)) 212 if (!cifs_convert_address(dst, src, len))
210 return 0; 213 return 0;
211 214
212 switch (dst->sa_family) { 215 switch (dst->sa_family) {