1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified for big endian by J.F. Chadima and David S. Miller
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 * Modified 1999 Wolfram Pienkoss for NLS
9 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17 static inline void assert_server_locked(struct ncp_server
*server
)
19 if (server
->lock
== 0) {
20 ncp_dbg(1, "server not locked!\n");
24 static void ncp_add_byte(struct ncp_server
*server
, __u8 x
)
26 assert_server_locked(server
);
27 *(__u8
*) (&(server
->packet
[server
->current_size
])) = x
;
28 server
->current_size
+= 1;
32 static void ncp_add_word(struct ncp_server
*server
, __le16 x
)
34 assert_server_locked(server
);
35 put_unaligned(x
, (__le16
*) (&(server
->packet
[server
->current_size
])));
36 server
->current_size
+= 2;
40 static void ncp_add_be16(struct ncp_server
*server
, __u16 x
)
42 assert_server_locked(server
);
43 put_unaligned(cpu_to_be16(x
), (__be16
*) (&(server
->packet
[server
->current_size
])));
44 server
->current_size
+= 2;
47 static void ncp_add_dword(struct ncp_server
*server
, __le32 x
)
49 assert_server_locked(server
);
50 put_unaligned(x
, (__le32
*) (&(server
->packet
[server
->current_size
])));
51 server
->current_size
+= 4;
55 static void ncp_add_be32(struct ncp_server
*server
, __u32 x
)
57 assert_server_locked(server
);
58 put_unaligned(cpu_to_be32(x
), (__be32
*)(&(server
->packet
[server
->current_size
])));
59 server
->current_size
+= 4;
62 static inline void ncp_add_dword_lh(struct ncp_server
*server
, __u32 x
) {
63 ncp_add_dword(server
, cpu_to_le32(x
));
66 static void ncp_add_mem(struct ncp_server
*server
, const void *source
, int size
)
68 assert_server_locked(server
);
69 memcpy(&(server
->packet
[server
->current_size
]), source
, size
);
70 server
->current_size
+= size
;
74 static void ncp_add_pstring(struct ncp_server
*server
, const char *s
)
77 assert_server_locked(server
);
79 ncp_dbg(1, "string too long: %s\n", s
);
82 ncp_add_byte(server
, len
);
83 ncp_add_mem(server
, s
, len
);
87 static inline void ncp_init_request(struct ncp_server
*server
)
89 ncp_lock_server(server
);
91 server
->current_size
= sizeof(struct ncp_request_header
);
92 server
->has_subfunction
= 0;
95 static inline void ncp_init_request_s(struct ncp_server
*server
, int subfunction
)
97 ncp_lock_server(server
);
99 server
->current_size
= sizeof(struct ncp_request_header
) + 2;
100 ncp_add_byte(server
, subfunction
);
102 server
->has_subfunction
= 1;
106 ncp_reply_data(struct ncp_server
*server
, int offset
)
108 return &(server
->packet
[sizeof(struct ncp_reply_header
) + offset
]);
111 static inline u8
BVAL(const void *data
)
113 return *(const u8
*)data
;
116 static u8
ncp_reply_byte(struct ncp_server
*server
, int offset
)
118 return *(const u8
*)ncp_reply_data(server
, offset
);
121 static inline u16
WVAL_LH(const void *data
)
123 return get_unaligned_le16(data
);
127 ncp_reply_le16(struct ncp_server
*server
, int offset
)
129 return get_unaligned_le16(ncp_reply_data(server
, offset
));
133 ncp_reply_be16(struct ncp_server
*server
, int offset
)
135 return get_unaligned_be16(ncp_reply_data(server
, offset
));
138 static inline u32
DVAL_LH(const void *data
)
140 return get_unaligned_le32(data
);
144 ncp_reply_dword(struct ncp_server
*server
, int offset
)
146 return get_unaligned((__le32
*)ncp_reply_data(server
, offset
));
149 static inline __u32
ncp_reply_dword_lh(struct ncp_server
* server
, int offset
) {
150 return le32_to_cpu(ncp_reply_dword(server
, offset
));
154 ncp_negotiate_buffersize(struct ncp_server
*server
, int size
, int *target
)
158 ncp_init_request(server
);
159 ncp_add_be16(server
, size
);
161 if ((result
= ncp_request(server
, 33)) != 0) {
162 ncp_unlock_server(server
);
165 *target
= min_t(unsigned int, ncp_reply_be16(server
, 0), size
);
167 ncp_unlock_server(server
);
174 * bit 1 packet signing
177 ncp_negotiate_size_and_options(struct ncp_server
*server
,
178 int size
, int options
, int *ret_size
, int *ret_options
) {
181 /* there is minimum */
182 if (size
< NCP_BLOCK_SIZE
) size
= NCP_BLOCK_SIZE
;
184 ncp_init_request(server
);
185 ncp_add_be16(server
, size
);
186 ncp_add_byte(server
, options
);
188 if ((result
= ncp_request(server
, 0x61)) != 0)
190 ncp_unlock_server(server
);
194 /* NCP over UDP returns 0 (!!!) */
195 result
= ncp_reply_be16(server
, 0);
196 if (result
>= NCP_BLOCK_SIZE
)
197 size
= min(result
, size
);
199 *ret_options
= ncp_reply_byte(server
, 4);
201 ncp_unlock_server(server
);
205 int ncp_get_volume_info_with_number(struct ncp_server
* server
,
206 int n
, struct ncp_volume_info
* target
) {
210 ncp_init_request_s(server
, 44);
211 ncp_add_byte(server
, n
);
213 if ((result
= ncp_request(server
, 22)) != 0) {
216 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
217 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
218 target
->purgeable_blocks
= ncp_reply_dword_lh(server
, 8);
219 target
->not_yet_purgeable_blocks
= ncp_reply_dword_lh(server
, 12);
220 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 16);
221 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 20);
222 target
->sectors_per_block
= ncp_reply_byte(server
, 28);
224 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
227 len
= ncp_reply_byte(server
, 29);
228 if (len
> NCP_VOLNAME_LEN
) {
229 ncp_dbg(1, "volume name too long: %d\n", len
);
232 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 30), len
);
235 ncp_unlock_server(server
);
239 int ncp_get_directory_info(struct ncp_server
* server
, __u8 n
,
240 struct ncp_volume_info
* target
) {
244 ncp_init_request_s(server
, 45);
245 ncp_add_byte(server
, n
);
247 if ((result
= ncp_request(server
, 22)) != 0) {
250 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
251 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
252 target
->purgeable_blocks
= 0;
253 target
->not_yet_purgeable_blocks
= 0;
254 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 8);
255 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 12);
256 target
->sectors_per_block
= ncp_reply_byte(server
, 20);
258 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
261 len
= ncp_reply_byte(server
, 21);
262 if (len
> NCP_VOLNAME_LEN
) {
263 ncp_dbg(1, "volume name too long: %d\n", len
);
266 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 22), len
);
269 ncp_unlock_server(server
);
274 ncp_close_file(struct ncp_server
*server
, const char *file_id
)
278 ncp_init_request(server
);
279 ncp_add_byte(server
, 0);
280 ncp_add_mem(server
, file_id
, 6);
282 result
= ncp_request(server
, 66);
283 ncp_unlock_server(server
);
288 ncp_make_closed(struct inode
*inode
)
293 mutex_lock(&NCP_FINFO(inode
)->open_mutex
);
294 if (atomic_read(&NCP_FINFO(inode
)->opened
) == 1) {
295 atomic_set(&NCP_FINFO(inode
)->opened
, 0);
296 err
= ncp_close_file(NCP_SERVER(inode
), NCP_FINFO(inode
)->file_handle
);
299 ncp_vdbg("volnum=%d, dirent=%u, error=%d\n",
300 NCP_FINFO(inode
)->volNumber
,
301 NCP_FINFO(inode
)->dirEntNum
, err
);
303 mutex_unlock(&NCP_FINFO(inode
)->open_mutex
);
307 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
308 __le32 dir_base
, int have_dir_base
,
311 ncp_add_byte(server
, vol_num
);
312 ncp_add_dword(server
, dir_base
);
313 if (have_dir_base
!= 0) {
314 ncp_add_byte(server
, 1); /* dir_base */
316 ncp_add_byte(server
, 0xff); /* no handle */
319 ncp_add_byte(server
, 1); /* 1 component */
320 ncp_add_pstring(server
, path
);
322 ncp_add_byte(server
, 0);
326 int ncp_dirhandle_alloc(struct ncp_server
* server
, __u8 volnum
, __le32 dirent
,
330 ncp_init_request(server
);
331 ncp_add_byte(server
, 12); /* subfunction */
332 ncp_add_byte(server
, NW_NS_DOS
);
333 ncp_add_byte(server
, 0);
334 ncp_add_word(server
, 0);
335 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
336 if ((result
= ncp_request(server
, 87)) == 0) {
337 *dirhandle
= ncp_reply_byte(server
, 0);
339 ncp_unlock_server(server
);
343 int ncp_dirhandle_free(struct ncp_server
* server
, __u8 dirhandle
) {
346 ncp_init_request_s(server
, 20);
347 ncp_add_byte(server
, dirhandle
);
348 result
= ncp_request(server
, 22);
349 ncp_unlock_server(server
);
353 void ncp_extract_file_info(const void *structure
, struct nw_info_struct
*target
)
355 const __u8
*name_len
;
356 const int info_struct_size
= offsetof(struct nw_info_struct
, nameLen
);
358 memcpy(target
, structure
, info_struct_size
);
359 name_len
= structure
+ info_struct_size
;
360 target
->nameLen
= *name_len
;
361 memcpy(target
->entryName
, name_len
+ 1, *name_len
);
362 target
->entryName
[*name_len
] = '\0';
363 target
->volNumber
= le32_to_cpu(target
->volNumber
);
367 #ifdef CONFIG_NCPFS_NFS_NS
368 static inline void ncp_extract_nfs_info(const unsigned char *structure
,
369 struct nw_nfs_info
*target
)
371 target
->mode
= DVAL_LH(structure
);
372 target
->rdev
= DVAL_LH(structure
+ 8);
376 int ncp_obtain_nfs_info(struct ncp_server
*server
,
377 struct nw_info_struct
*target
)
381 #ifdef CONFIG_NCPFS_NFS_NS
382 __u32 volnum
= target
->volNumber
;
384 if (ncp_is_nfs_extras(server
, volnum
)) {
385 ncp_init_request(server
);
386 ncp_add_byte(server
, 19); /* subfunction */
387 ncp_add_byte(server
, server
->name_space
[volnum
]);
388 ncp_add_byte(server
, NW_NS_NFS
);
389 ncp_add_byte(server
, 0);
390 ncp_add_byte(server
, volnum
);
391 ncp_add_dword(server
, target
->dirEntNum
);
392 /* We must retrieve both nlinks and rdev, otherwise some server versions
393 report zeroes instead of valid data */
394 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
396 if ((result
= ncp_request(server
, 87)) == 0) {
397 ncp_extract_nfs_info(ncp_reply_data(server
, 0), &target
->nfs
);
398 ncp_dbg(1, "(%s) mode=0%o, rdev=0x%x\n",
399 target
->entryName
, target
->nfs
.mode
,
402 target
->nfs
.mode
= 0;
403 target
->nfs
.rdev
= 0;
405 ncp_unlock_server(server
);
410 target
->nfs
.mode
= 0;
411 target
->nfs
.rdev
= 0;
417 * Returns information for a (one-component) name relative to
418 * the specified directory.
420 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, const char *path
,
421 struct nw_info_struct
*target
)
423 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
424 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
427 if (target
== NULL
) {
428 pr_err("%s: invalid call\n", __func__
);
431 ncp_init_request(server
);
432 ncp_add_byte(server
, 6); /* subfunction */
433 ncp_add_byte(server
, server
->name_space
[volnum
]);
434 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
435 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
436 ncp_add_dword(server
, RIM_ALL
);
437 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
439 if ((result
= ncp_request(server
, 87)) != 0)
441 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
442 ncp_unlock_server(server
);
444 result
= ncp_obtain_nfs_info(server
, target
);
448 ncp_unlock_server(server
);
452 #ifdef CONFIG_NCPFS_NFS_NS
454 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
455 __u8 ns
, __u8 volnum
, __le32 dirent
,
456 const char *path
, /* At most 1 component */
457 __le32
*DOS_dir_base
)
461 ncp_init_request(server
);
462 ncp_add_byte(server
, 6); /* subfunction */
463 ncp_add_byte(server
, ns
);
464 ncp_add_byte(server
, ns
);
465 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
466 ncp_add_dword(server
, RIM_DIRECTORY
);
467 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
469 if ((result
= ncp_request(server
, 87)) == 0)
471 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
473 ncp_unlock_server(server
);
476 #endif /* CONFIG_NCPFS_NFS_NS */
479 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
481 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
486 ncp_init_request(server
);
487 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
488 ncp_add_word(server
, 0);
489 ncp_add_byte(server
, volume
);
491 if ((result
= ncp_request(server
, 87)) != 0) {
492 ncp_unlock_server(server
);
493 return NW_NS_DOS
; /* not result ?? */
497 no_namespaces
= ncp_reply_le16(server
, 0);
498 namespace = ncp_reply_data(server
, 2);
500 while (no_namespaces
> 0) {
501 ncp_dbg(1, "found %d on %d\n", *namespace, volume
);
503 #ifdef CONFIG_NCPFS_NFS_NS
504 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
509 #endif /* CONFIG_NCPFS_NFS_NS */
510 #ifdef CONFIG_NCPFS_OS2_NS
511 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
515 #endif /* CONFIG_NCPFS_OS2_NS */
519 ncp_unlock_server(server
);
521 #else /* neither OS2 nor NFS - only DOS */
523 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
527 ncp_update_known_namespace(struct ncp_server
*server
, __u8 volume
, int *ret_ns
)
529 int ns
= ncp_get_known_namespace(server
, volume
);
534 ncp_dbg(1, "namespace[%d] = %d\n", volume
, server
->name_space
[volume
]);
536 if (server
->name_space
[volume
] == ns
)
538 server
->name_space
[volume
] = ns
;
543 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
544 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
545 const char *path
, /* At most 1 component */
546 __le32
*dirEntNum
, __le32
*DosDirNum
)
550 ncp_init_request(server
);
551 ncp_add_byte(server
, 6); /* subfunction */
552 ncp_add_byte(server
, nsSrc
);
553 ncp_add_byte(server
, nsDst
);
554 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
555 ncp_add_dword(server
, RIM_ALL
);
556 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
558 if ((result
= ncp_request(server
, 87)) != 0)
560 ncp_unlock_server(server
);
565 *dirEntNum
= ncp_reply_dword(server
, 0x30);
567 *DosDirNum
= ncp_reply_dword(server
, 0x34);
568 ncp_unlock_server(server
);
573 ncp_mount_subdir(struct ncp_server
*server
,
574 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
575 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
580 ncp_update_known_namespace(server
, volNumber
, &dstNS
);
581 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
582 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
587 server
->m
.mounted_vol
[1] = 0;
588 server
->m
.mounted_vol
[0] = 'X';
593 ncp_get_volume_root(struct ncp_server
*server
,
594 const char *volname
, __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
598 ncp_dbg(1, "looking up vol %s\n", volname
);
600 ncp_init_request(server
);
601 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
602 ncp_add_byte(server
, 0); /* DOS namespace */
603 ncp_add_byte(server
, 0); /* reserved */
604 ncp_add_byte(server
, 0); /* reserved */
605 ncp_add_byte(server
, 0); /* reserved */
607 ncp_add_byte(server
, 0); /* faked volume number */
608 ncp_add_dword(server
, 0); /* faked dir_base */
609 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
610 ncp_add_byte(server
, 1); /* 1 path component */
611 ncp_add_pstring(server
, volname
);
613 if ((result
= ncp_request(server
, 87)) != 0) {
614 ncp_unlock_server(server
);
617 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
618 *volume
= ncp_reply_byte(server
, 8);
619 ncp_unlock_server(server
);
624 ncp_lookup_volume(struct ncp_server
*server
,
625 const char *volname
, struct nw_info_struct
*target
)
629 memset(target
, 0, sizeof(*target
));
630 result
= ncp_get_volume_root(server
, volname
,
631 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
635 ncp_update_known_namespace(server
, target
->volNumber
, NULL
);
636 target
->nameLen
= strlen(volname
);
637 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
638 target
->attributes
= aDIR
;
639 /* set dates to Jan 1, 1986 00:00 */
640 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
641 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
642 target
->nfs
.mode
= 0;
646 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
650 const struct nw_modify_dos_info
*info
)
652 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
653 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
656 ncp_init_request(server
);
657 ncp_add_byte(server
, 7); /* subfunction */
658 ncp_add_byte(server
, server
->name_space
[volnum
]);
659 ncp_add_byte(server
, 0); /* reserved */
660 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
662 ncp_add_dword(server
, info_mask
);
663 ncp_add_mem(server
, info
, sizeof(*info
));
664 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
666 result
= ncp_request(server
, 87);
667 ncp_unlock_server(server
);
671 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
674 const struct nw_modify_dos_info
*info
)
676 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
680 #ifdef CONFIG_NCPFS_NFS_NS
681 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
682 __u32 mode
, __u32 rdev
)
687 ncp_init_request(server
);
688 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
689 ncp_add_byte(server
, 25); /* subfunction */
690 ncp_add_byte(server
, server
->name_space
[volnum
]);
691 ncp_add_byte(server
, NW_NS_NFS
);
692 ncp_add_byte(server
, volnum
);
693 ncp_add_dword(server
, dirent
);
694 /* we must always operate on both nlinks and rdev, otherwise
696 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
697 ncp_add_dword_lh(server
, mode
);
698 ncp_add_dword_lh(server
, 1); /* nlinks */
699 ncp_add_dword_lh(server
, rdev
);
700 result
= ncp_request(server
, 87);
702 ncp_unlock_server(server
);
709 ncp_DeleteNSEntry(struct ncp_server
*server
,
710 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
711 const char* name
, __u8 ns
, __le16 attr
)
715 ncp_init_request(server
);
716 ncp_add_byte(server
, 8); /* subfunction */
717 ncp_add_byte(server
, ns
);
718 ncp_add_byte(server
, 0); /* reserved */
719 ncp_add_word(server
, attr
); /* search attribs: all */
720 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
722 result
= ncp_request(server
, 87);
723 ncp_unlock_server(server
);
728 ncp_del_file_or_subdir2(struct ncp_server
*server
,
729 struct dentry
*dentry
)
731 struct inode
*inode
= d_inode(dentry
);
736 return 0xFF; /* Any error */
738 volnum
= NCP_FINFO(inode
)->volNumber
;
739 dirent
= NCP_FINFO(inode
)->DosDirNum
;
740 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
744 ncp_del_file_or_subdir(struct ncp_server
*server
,
745 struct inode
*dir
, const char *name
)
747 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
748 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
751 name_space
= server
->name_space
[volnum
];
752 #ifdef CONFIG_NCPFS_NFS_NS
753 if (name_space
== NW_NS_NFS
)
757 result
=ncp_obtain_DOS_dir_base(server
, name_space
, volnum
, dirent
, name
, &dirent
);
758 if (result
) return result
;
760 name_space
= NW_NS_DOS
;
762 #endif /* CONFIG_NCPFS_NFS_NS */
763 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, name_space
, cpu_to_le16(0x8006));
766 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
768 __le16
*dest
= (__le16
*) ret
;
769 dest
[1] = cpu_to_le16(v0
);
770 dest
[2] = cpu_to_le16(v1
);
771 dest
[0] = cpu_to_le16(v0
+ 1);
775 /* If both dir and name are NULL, then in target there's already a
776 looked-up entry that wants to be opened. */
777 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
778 struct inode
*dir
, const char *name
,
779 int open_create_mode
,
780 __le32 create_attributes
,
781 __le16 desired_acc_rights
,
782 struct ncp_entry_info
*target
)
784 __le16 search_attribs
= cpu_to_le16(0x0006);
789 volnum
= NCP_FINFO(dir
)->volNumber
;
790 dirent
= NCP_FINFO(dir
)->dirEntNum
;
792 if ((create_attributes
& aDIR
) != 0) {
793 search_attribs
|= cpu_to_le16(0x8000);
795 ncp_init_request(server
);
796 ncp_add_byte(server
, 1); /* subfunction */
797 ncp_add_byte(server
, server
->name_space
[volnum
]);
798 ncp_add_byte(server
, open_create_mode
);
799 ncp_add_word(server
, search_attribs
);
800 ncp_add_dword(server
, RIM_ALL
);
801 ncp_add_dword(server
, create_attributes
);
802 /* The desired acc rights seem to be the inherited rights mask
804 ncp_add_word(server
, desired_acc_rights
);
805 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
807 if ((result
= ncp_request(server
, 87)) != 0)
809 if (!(create_attributes
& aDIR
))
812 /* in target there's a new finfo to fill */
813 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
814 target
->volume
= target
->i
.volNumber
;
815 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
816 ncp_reply_le16(server
, 2),
817 target
->file_handle
);
819 ncp_unlock_server(server
);
821 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
825 ncp_unlock_server(server
);
830 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
831 struct nw_search_sequence
*target
)
833 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
834 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
837 ncp_init_request(server
);
838 ncp_add_byte(server
, 2); /* subfunction */
839 ncp_add_byte(server
, server
->name_space
[volnum
]);
840 ncp_add_byte(server
, 0); /* reserved */
841 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
843 result
= ncp_request(server
, 87);
846 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
849 ncp_unlock_server(server
);
853 int ncp_search_for_fileset(struct ncp_server
*server
,
854 struct nw_search_sequence
*seq
,
864 ncp_init_request(server
);
865 ncp_add_byte(server
, 20);
866 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
867 ncp_add_byte(server
, 0); /* datastream */
868 ncp_add_word(server
, cpu_to_le16(0x8006));
869 ncp_add_dword(server
, RIM_ALL
);
870 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
871 ncp_add_mem(server
, seq
, 9);
872 #ifdef CONFIG_NCPFS_NFS_NS
873 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
874 ncp_add_byte(server
, 0); /* 0 byte pattern */
878 ncp_add_byte(server
, 2); /* 2 byte pattern */
879 ncp_add_byte(server
, 0xff); /* following is a wildcard */
880 ncp_add_byte(server
, '*');
882 result
= ncp_request2(server
, 87, buffer
, bufsize
);
884 ncp_unlock_server(server
);
887 if (server
->ncp_reply_size
< 12) {
888 ncp_unlock_server(server
);
891 *rsize
= server
->ncp_reply_size
- 12;
892 ncp_unlock_server(server
);
893 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
895 *cnt
= WVAL_LH(buffer
+ 10);
896 *more
= BVAL(buffer
+ 9);
897 memcpy(seq
, buffer
, 9);
902 ncp_RenameNSEntry(struct ncp_server
*server
,
903 struct inode
*old_dir
, const char *old_name
, __le16 old_type
,
904 struct inode
*new_dir
, const char *new_name
)
906 int result
= -EINVAL
;
908 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
909 (new_dir
== NULL
) || (new_name
== NULL
))
912 ncp_init_request(server
);
913 ncp_add_byte(server
, 4); /* subfunction */
914 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
915 ncp_add_byte(server
, 1); /* rename flag */
916 ncp_add_word(server
, old_type
); /* search attributes */
918 /* source Handle Path */
919 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
920 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
921 ncp_add_byte(server
, 1);
922 ncp_add_byte(server
, 1); /* 1 source component */
924 /* dest Handle Path */
925 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
926 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
927 ncp_add_byte(server
, 1);
928 ncp_add_byte(server
, 1); /* 1 destination component */
930 /* source path string */
931 ncp_add_pstring(server
, old_name
);
932 /* dest path string */
933 ncp_add_pstring(server
, new_name
);
935 result
= ncp_request(server
, 87);
936 ncp_unlock_server(server
);
941 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
942 struct inode
*old_dir
, const char *old_name
,
943 struct inode
*new_dir
, const char *new_name
)
946 __le16 old_type
= cpu_to_le16(0x06);
948 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
949 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
951 if (result
== 0xFF) /* File Not Found, try directory */
953 old_type
= cpu_to_le16(0x16);
954 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
957 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
958 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
959 if (result
!= 0) return -EACCES
;
960 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
966 /* We have to transfer to/from user space */
968 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
969 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
974 ncp_init_request(server
);
975 ncp_add_byte(server
, 0);
976 ncp_add_mem(server
, file_id
, 6);
977 ncp_add_be32(server
, offset
);
978 ncp_add_be16(server
, to_read
);
980 if ((result
= ncp_request(server
, 72)) != 0) {
983 *bytes_read
= ncp_reply_be16(server
, 0);
984 if (*bytes_read
> to_read
) {
988 source
= ncp_reply_data(server
, 2 + (offset
& 1));
990 memcpy(target
, source
, *bytes_read
);
992 ncp_unlock_server(server
);
996 /* There is a problem... egrep and some other silly tools do:
997 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
998 read(<ncpfs fd>, x, 32768);
999 Now copying read result by copy_to_user causes pagefault. This pagefault
1000 could not be handled because of server was locked due to read. So we have
1001 to use temporary buffer. So ncp_unlock_server must be done before
1002 copy_to_user (and for write, copy_from_user must be done before
1003 ncp_init_request... same applies for send raw packet ioctl). Because of
1004 file is normally read in bigger chunks, caller provides kmalloced
1005 (vmalloced) chunk of memory with size >= to_read...
1008 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
1009 __u32 offset
, __u16 to_read
, struct iov_iter
*to
,
1010 int *bytes_read
, void *bounce
, __u32 bufsize
)
1014 ncp_init_request(server
);
1015 ncp_add_byte(server
, 0);
1016 ncp_add_mem(server
, file_id
, 6);
1017 ncp_add_be32(server
, offset
);
1018 ncp_add_be16(server
, to_read
);
1019 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1020 ncp_unlock_server(server
);
1022 int len
= get_unaligned_be16((char *)bounce
+
1023 sizeof(struct ncp_reply_header
));
1025 if (len
<= to_read
) {
1028 source
= (char*)bounce
+
1029 sizeof(struct ncp_reply_header
) + 2 +
1033 if (copy_to_iter(source
, len
, to
) != len
)
1041 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1042 __u32 offset
, __u16 to_write
,
1043 const char *source
, int *bytes_written
)
1047 ncp_init_request(server
);
1048 ncp_add_byte(server
, 0);
1049 ncp_add_mem(server
, file_id
, 6);
1050 ncp_add_be32(server
, offset
);
1051 ncp_add_be16(server
, to_write
);
1052 ncp_add_mem(server
, source
, to_write
);
1054 if ((result
= ncp_request(server
, 73)) == 0)
1055 *bytes_written
= to_write
;
1056 ncp_unlock_server(server
);
1060 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1062 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1063 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1067 ncp_init_request(server
);
1068 ncp_add_byte(server
, locktype
);
1069 ncp_add_mem(server
, file_id
, 6);
1070 ncp_add_be32(server
, offset
);
1071 ncp_add_be32(server
, length
);
1072 ncp_add_be16(server
, timeout
);
1074 if ((result
= ncp_request(server
, 0x1A)) != 0)
1076 ncp_unlock_server(server
);
1079 ncp_unlock_server(server
);
1084 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1085 __u32 offset
, __u32 length
)
1089 ncp_init_request(server
);
1090 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1091 ncp_add_mem(server
, file_id
, 6);
1092 ncp_add_be32(server
, offset
);
1093 ncp_add_be32(server
, length
);
1095 if ((result
= ncp_request(server
, 0x1E)) != 0)
1097 ncp_unlock_server(server
);
1100 ncp_unlock_server(server
);
1103 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1105 #ifdef CONFIG_NCPFS_NLS
1106 /* This are the NLS conversion routines with inspirations and code parts
1107 * from the vfat file system and hints from Petr Vandrovec.
1111 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1112 const unsigned char *iname
, unsigned int ilen
, int cc
)
1114 struct nls_table
*in
= server
->nls_io
;
1115 struct nls_table
*out
= server
->nls_vol
;
1116 unsigned char *vname_start
;
1117 unsigned char *vname_end
;
1118 const unsigned char *iname_end
;
1120 iname_end
= iname
+ ilen
;
1121 vname_start
= vname
;
1122 vname_end
= vname
+ *vlen
- 1;
1124 while (iname
< iname_end
) {
1128 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1132 k
= utf8_to_utf32(iname
, iname_end
- iname
, &u
);
1133 if (k
< 0 || u
> MAX_WCHAR_T
)
1138 if (*iname
== NCP_ESC
) {
1141 if (iname_end
- iname
< 5)
1145 for (k
= 1; k
< 5; k
++) {
1148 nc
= iname
[k
] - '0';
1150 nc
-= 'A' - '0' - 10;
1151 if ((nc
< 10) || (nc
> 15)) {
1155 ec
= (ec
<< 4) | nc
;
1160 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1166 /* unitoupper should be here! */
1168 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1172 /* this is wrong... */
1176 for (chi
= 0; chi
< chl
; chi
++){
1177 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1184 *vlen
= vname
- vname_start
;
1189 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1190 const unsigned char *vname
, unsigned int vlen
, int cc
)
1192 struct nls_table
*in
= server
->nls_vol
;
1193 struct nls_table
*out
= server
->nls_io
;
1194 const unsigned char *vname_end
;
1195 unsigned char *iname_start
;
1196 unsigned char *iname_end
;
1197 unsigned char *vname_cc
;
1205 /* this is wrong! */
1206 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1209 for (i
= 0; i
< vlen
; i
++)
1210 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1214 iname_start
= iname
;
1215 iname_end
= iname
+ *ilen
- 1;
1216 vname_end
= vname
+ vlen
;
1218 while (vname
< vname_end
) {
1222 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1228 /* unitolower should be here! */
1230 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1233 k
= utf32_to_utf8(ec
, iname
, iname_end
- iname
);
1235 err
= -ENAMETOOLONG
;
1240 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1245 if (iname_end
- iname
< 5) {
1246 err
= -ENAMETOOLONG
;
1250 for (k
= 4; k
> 0; k
--) {
1253 v
= (ec
& 0xF) + '0';
1266 *ilen
= iname
- iname_start
;
1277 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1278 const unsigned char *iname
, unsigned int ilen
, int cc
)
1283 return -ENAMETOOLONG
;
1286 for (i
= 0; i
< ilen
; i
++) {
1287 *vname
= toupper(*iname
);
1292 memmove(vname
, iname
, ilen
);
1302 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1303 const unsigned char *vname
, unsigned int vlen
, int cc
)
1308 return -ENAMETOOLONG
;
1311 for (i
= 0; i
< vlen
; i
++) {
1312 *iname
= tolower(*vname
);
1317 memmove(iname
, vname
, vlen
);