162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2022 Paulo Alcantara <palcantara@suse.de> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#ifndef _CIFS_DFS_H 762306a36Sopenharmony_ci#define _CIFS_DFS_H 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include "cifsglob.h" 1062306a36Sopenharmony_ci#include "fs_context.h" 1162306a36Sopenharmony_ci#include "cifs_unicode.h" 1262306a36Sopenharmony_ci#include <linux/namei.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define DFS_INTERLINK(v) \ 1562306a36Sopenharmony_ci (((v) & DFSREF_REFERRAL_SERVER) && !((v) & DFSREF_STORAGE_SERVER)) 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_cistruct dfs_ref { 1862306a36Sopenharmony_ci char *path; 1962306a36Sopenharmony_ci char *full_path; 2062306a36Sopenharmony_ci struct dfs_cache_tgt_list tl; 2162306a36Sopenharmony_ci struct dfs_cache_tgt_iterator *tit; 2262306a36Sopenharmony_ci}; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct dfs_ref_walk { 2562306a36Sopenharmony_ci struct dfs_ref *ref; 2662306a36Sopenharmony_ci struct dfs_ref refs[MAX_NESTED_LINKS]; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define ref_walk_start(w) ((w)->refs) 3062306a36Sopenharmony_ci#define ref_walk_end(w) (&(w)->refs[ARRAY_SIZE((w)->refs) - 1]) 3162306a36Sopenharmony_ci#define ref_walk_cur(w) ((w)->ref) 3262306a36Sopenharmony_ci#define ref_walk_descend(w) (--ref_walk_cur(w) >= ref_walk_start(w)) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define ref_walk_tit(w) (ref_walk_cur(w)->tit) 3562306a36Sopenharmony_ci#define ref_walk_empty(w) (!ref_walk_tit(w)) 3662306a36Sopenharmony_ci#define ref_walk_path(w) (ref_walk_cur(w)->path) 3762306a36Sopenharmony_ci#define ref_walk_fpath(w) (ref_walk_cur(w)->full_path) 3862306a36Sopenharmony_ci#define ref_walk_tl(w) (&ref_walk_cur(w)->tl) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic inline struct dfs_ref_walk *ref_walk_alloc(void) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct dfs_ref_walk *rw; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci rw = kmalloc(sizeof(*rw), GFP_KERNEL); 4562306a36Sopenharmony_ci if (!rw) 4662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 4762306a36Sopenharmony_ci return rw; 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic inline void ref_walk_init(struct dfs_ref_walk *rw) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci memset(rw, 0, sizeof(*rw)); 5362306a36Sopenharmony_ci ref_walk_cur(rw) = ref_walk_start(rw); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic inline void __ref_walk_free(struct dfs_ref *ref) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci kfree(ref->path); 5962306a36Sopenharmony_ci kfree(ref->full_path); 6062306a36Sopenharmony_ci dfs_cache_free_tgts(&ref->tl); 6162306a36Sopenharmony_ci memset(ref, 0, sizeof(*ref)); 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic inline void ref_walk_free(struct dfs_ref_walk *rw) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci struct dfs_ref *ref = ref_walk_start(rw); 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci for (; ref <= ref_walk_end(rw); ref++) 6962306a36Sopenharmony_ci __ref_walk_free(ref); 7062306a36Sopenharmony_ci kfree(rw); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic inline int ref_walk_advance(struct dfs_ref_walk *rw) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct dfs_ref *ref = ref_walk_cur(rw) + 1; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci if (ref > ref_walk_end(rw)) 7862306a36Sopenharmony_ci return -ELOOP; 7962306a36Sopenharmony_ci __ref_walk_free(ref); 8062306a36Sopenharmony_ci ref_walk_cur(rw) = ref; 8162306a36Sopenharmony_ci return 0; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_cistatic inline struct dfs_cache_tgt_iterator * 8562306a36Sopenharmony_ciref_walk_next_tgt(struct dfs_ref_walk *rw) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci struct dfs_cache_tgt_iterator *tit; 8862306a36Sopenharmony_ci struct dfs_ref *ref = ref_walk_cur(rw); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (!ref->tit) 9162306a36Sopenharmony_ci tit = dfs_cache_get_tgt_iterator(&ref->tl); 9262306a36Sopenharmony_ci else 9362306a36Sopenharmony_ci tit = dfs_cache_get_next_tgt(&ref->tl, ref->tit); 9462306a36Sopenharmony_ci ref->tit = tit; 9562306a36Sopenharmony_ci return tit; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline int ref_walk_get_tgt(struct dfs_ref_walk *rw, 9962306a36Sopenharmony_ci struct dfs_info3_param *tgt) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci zfree_dfs_info_param(tgt); 10262306a36Sopenharmony_ci return dfs_cache_get_tgt_referral(ref_walk_path(rw) + 1, 10362306a36Sopenharmony_ci ref_walk_tit(rw), tgt); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic inline int ref_walk_num_tgts(struct dfs_ref_walk *rw) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci return dfs_cache_get_nr_tgts(ref_walk_tl(rw)); 10962306a36Sopenharmony_ci} 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic inline void ref_walk_set_tgt_hint(struct dfs_ref_walk *rw) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci dfs_cache_noreq_update_tgthint(ref_walk_path(rw) + 1, 11462306a36Sopenharmony_ci ref_walk_tit(rw)); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistruct dfs_root_ses { 11862306a36Sopenharmony_ci struct list_head list; 11962306a36Sopenharmony_ci struct cifs_ses *ses; 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciint dfs_parse_target_referral(const char *full_path, const struct dfs_info3_param *ref, 12362306a36Sopenharmony_ci struct smb3_fs_context *ctx); 12462306a36Sopenharmony_ciint dfs_mount_share(struct cifs_mount_ctx *mnt_ctx, bool *isdfs); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic inline char *dfs_get_path(struct cifs_sb_info *cifs_sb, const char *path) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci return dfs_cache_canonical_path(path, cifs_sb->local_nls, cifs_remap(cifs_sb)); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_cistatic inline int dfs_get_referral(struct cifs_mount_ctx *mnt_ctx, const char *path, 13262306a36Sopenharmony_ci struct dfs_info3_param *ref, struct dfs_cache_tgt_list *tl) 13362306a36Sopenharmony_ci{ 13462306a36Sopenharmony_ci struct smb3_fs_context *ctx = mnt_ctx->fs_ctx; 13562306a36Sopenharmony_ci struct cifs_sb_info *cifs_sb = mnt_ctx->cifs_sb; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return dfs_cache_find(mnt_ctx->xid, ctx->dfs_root_ses, cifs_sb->local_nls, 13862306a36Sopenharmony_ci cifs_remap(cifs_sb), path, ref, tl); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic inline void dfs_put_root_smb_sessions(struct list_head *head) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct dfs_root_ses *root, *tmp; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci list_for_each_entry_safe(root, tmp, head, list) { 14662306a36Sopenharmony_ci list_del_init(&root->list); 14762306a36Sopenharmony_ci cifs_put_smb_ses(root->ses); 14862306a36Sopenharmony_ci kfree(root); 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci#endif /* _CIFS_DFS_H */ 153