162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OCB mode implementation
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright: (c) 2014 Czech Technical University in Prague
662306a36Sopenharmony_ci *            (c) 2014 Volkswagen Group Research
762306a36Sopenharmony_ci * Copyright (C) 2022 Intel Corporation
862306a36Sopenharmony_ci * Author:    Rostislav Lisovy <rostislav.lisovy@fel.cvut.cz>
962306a36Sopenharmony_ci * Funded by: Volkswagen Group Research
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/ieee80211.h>
1362306a36Sopenharmony_ci#include <net/cfg80211.h>
1462306a36Sopenharmony_ci#include "nl80211.h"
1562306a36Sopenharmony_ci#include "core.h"
1662306a36Sopenharmony_ci#include "rdev-ops.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciint __cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
1962306a36Sopenharmony_ci			struct net_device *dev,
2062306a36Sopenharmony_ci			struct ocb_setup *setup)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
2362306a36Sopenharmony_ci	int err;
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	ASSERT_WDEV_LOCK(wdev);
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
2862306a36Sopenharmony_ci		return -EOPNOTSUPP;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	if (!rdev->ops->join_ocb)
3162306a36Sopenharmony_ci		return -EOPNOTSUPP;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	if (WARN_ON(!setup->chandef.chan))
3462306a36Sopenharmony_ci		return -EINVAL;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	err = rdev_join_ocb(rdev, dev, setup);
3762306a36Sopenharmony_ci	if (!err)
3862306a36Sopenharmony_ci		wdev->u.ocb.chandef = setup->chandef;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	return err;
4162306a36Sopenharmony_ci}
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ciint cfg80211_join_ocb(struct cfg80211_registered_device *rdev,
4462306a36Sopenharmony_ci		      struct net_device *dev,
4562306a36Sopenharmony_ci		      struct ocb_setup *setup)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
4862306a36Sopenharmony_ci	int err;
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci	wdev_lock(wdev);
5162306a36Sopenharmony_ci	err = __cfg80211_join_ocb(rdev, dev, setup);
5262306a36Sopenharmony_ci	wdev_unlock(wdev);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	return err;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ciint __cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
5862306a36Sopenharmony_ci			 struct net_device *dev)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
6162306a36Sopenharmony_ci	int err;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	ASSERT_WDEV_LOCK(wdev);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_OCB)
6662306a36Sopenharmony_ci		return -EOPNOTSUPP;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (!rdev->ops->leave_ocb)
6962306a36Sopenharmony_ci		return -EOPNOTSUPP;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	if (!wdev->u.ocb.chandef.chan)
7262306a36Sopenharmony_ci		return -ENOTCONN;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	err = rdev_leave_ocb(rdev, dev);
7562306a36Sopenharmony_ci	if (!err)
7662306a36Sopenharmony_ci		memset(&wdev->u.ocb.chandef, 0, sizeof(wdev->u.ocb.chandef));
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	return err;
7962306a36Sopenharmony_ci}
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ciint cfg80211_leave_ocb(struct cfg80211_registered_device *rdev,
8262306a36Sopenharmony_ci		       struct net_device *dev)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct wireless_dev *wdev = dev->ieee80211_ptr;
8562306a36Sopenharmony_ci	int err;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	wdev_lock(wdev);
8862306a36Sopenharmony_ci	err = __cfg80211_leave_ocb(rdev, dev);
8962306a36Sopenharmony_ci	wdev_unlock(wdev);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	return err;
9262306a36Sopenharmony_ci}
93