18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OCB mode implementation
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright: (c) 2014 Czech Technical University in Prague
68c2ecf20Sopenharmony_ci *            (c) 2014 Volkswagen Group Research
78c2ecf20Sopenharmony_ci * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
88c2ecf20Sopenharmony_ci * Funded by: Volkswagen Group Research
98c2ecf20Sopenharmony_ci */
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/ieee80211.h>
128c2ecf20Sopenharmony_ci#include <net/cfg80211.h>
138c2ecf20Sopenharmony_ci#include "nl80211.h"
148c2ecf20Sopenharmony_ci#include "core.h"
158c2ecf20Sopenharmony_ci#include "rdev-ops.h"
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ciint __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
188c2ecf20Sopenharmony_ci			struct net_device *dev,
198c2ecf20Sopenharmony_ci			struct ocb_setup *setup)
208c2ecf20Sopenharmony_ci{
218c2ecf20Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
228c2ecf20Sopenharmony_ci	int err;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	ASSERT_WDEV_LOCK(wdev);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
278c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci	if (!rdev->ops->join_ocb)
308c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	if (WARN_ON(!setup->chandef.chan))
338c2ecf20Sopenharmony_ci		return -EINVAL;
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci	err = rdev_join_ocb(rdev, dev, setup);
368c2ecf20Sopenharmony_ci	if (!err)
378c2ecf20Sopenharmony_ci		wdev->chandef = setup->chandef;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	return err;
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ciint cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
438c2ecf20Sopenharmony_ci		      struct net_device *dev,
448c2ecf20Sopenharmony_ci		      struct ocb_setup *setup)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
478c2ecf20Sopenharmony_ci	int err;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	wdev_lock(wdev);
508c2ecf20Sopenharmony_ci	err = __cfg80211_join_ocb(rdev, dev, setup);
518c2ecf20Sopenharmony_ci	wdev_unlock(wdev);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	return err;
548c2ecf20Sopenharmony_ci}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciint __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
578c2ecf20Sopenharmony_ci			 struct net_device *dev)
588c2ecf20Sopenharmony_ci{
598c2ecf20Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
608c2ecf20Sopenharmony_ci	int err;
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ci	ASSERT_WDEV_LOCK(wdev);
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
658c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (!rdev->ops->leave_ocb)
688c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	err = rdev_leave_ocb(rdev, dev);
718c2ecf20Sopenharmony_ci	if (!err)
728c2ecf20Sopenharmony_ci		memset(&wdev->chandef, 0, sizeof(wdev->chandef));
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	return err;
758c2ecf20Sopenharmony_ci}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ciint cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
788c2ecf20Sopenharmony_ci		       struct net_device *dev)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
818c2ecf20Sopenharmony_ci	int err;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	wdev_lock(wdev);
848c2ecf20Sopenharmony_ci	err = __cfg80211_leave_ocb(rdev, dev);
858c2ecf20Sopenharmony_ci	wdev_unlock(wdev);
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	return err;
888c2ecf20Sopenharmony_ci}
89