1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Ultra Wide Band
4  * Dynamic Reservation Protocol handling
5  *
6  * Copyright (C) 2005-2006 Intel Corporation
7  * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
8  * Copyright (C) 2008 Cambridge Silicon Radio Ltd.
9  */
10 #include <linux/kthread.h>
11 #include <linux/freezer.h>
12 #include <linux/slab.h>
13 #include <linux/delay.h>
14 #include "uwb-internal.h"
15 
16 
17 /* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
18 enum uwb_drp_conflict_action {
19 	/* Reservation is maintained, no action needed */
20 	UWB_DRP_CONFLICT_MANTAIN = 0,
21 
22 	/* the device shall not transmit frames in conflicting MASs in
23 	 * the following superframe. If the device is the reservation
24 	 * target, it shall also set the Reason Code in its DRP IE to
25 	 * Conflict in its beacon in the following superframe.
26 	 */
27 	UWB_DRP_CONFLICT_ACT1,
28 
29 	/* the device shall not set the Reservation Status bit to ONE
30 	 * and shall not transmit frames in conflicting MASs. If the
31 	 * device is the reservation target, it shall also set the
32 	 * Reason Code in its DRP IE to Conflict.
33 	 */
34 	UWB_DRP_CONFLICT_ACT2,
35 
36 	/* the device shall not transmit frames in conflicting MASs in
37 	 * the following superframe. It shall remove the conflicting
38 	 * MASs from the reservation or set the Reservation Status to
39 	 * ZERO in its beacon in the following superframe. If the
40 	 * device is the reservation target, it shall also set the
41 	 * Reason Code in its DRP IE to Conflict.
42 	 */
43 	UWB_DRP_CONFLICT_ACT3,
44 };
45 
46 
uwb_rc_set_drp_cmd_done(struct uwb_rc * rc,void * arg,struct uwb_rceb * reply,ssize_t reply_size)47 static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
48 				    struct uwb_rceb *reply, ssize_t reply_size)
49 {
50 	struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
51 	unsigned long flags;
52 
53 	if (r != NULL) {
54 		if (r->bResultCode != UWB_RC_RES_SUCCESS)
55 			dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
56 				uwb_rc_strerror(r->bResultCode), r->bResultCode);
57 	} else
58 		dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
59 
60 	spin_lock_irqsave(&rc->rsvs_lock, flags);
61 	if (rc->set_drp_ie_pending > 1) {
62 		rc->set_drp_ie_pending = 0;
63 		uwb_rsv_queue_update(rc);
64 	} else {
65 		rc->set_drp_ie_pending = 0;
66 	}
67 	spin_unlock_irqrestore(&rc->rsvs_lock, flags);
68 }
69 
70 /**
71  * Construct and send the SET DRP IE
72  *
73  * @rc:         UWB Host controller
74  * @returns:    >= 0 number of bytes still available in the beacon
75  *              < 0 errno code on error.
76  *
77  * See WUSB[8.6.2.7]: The host must set all the DRP IEs that it wants the
78  * device to include in its beacon at the same time. We thus have to
79  * traverse all reservations and include the DRP IEs of all PENDING
80  * and NEGOTIATED reservations in a SET DRP command for transmission.
81  *
82  * A DRP Availability IE is appended.
83  *
84  * rc->rsvs_mutex is held
85  *
86  * FIXME We currently ignore the returned value indicating the remaining space
87  * in beacon. This could be used to deny reservation requests earlier if
88  * determined that they would cause the beacon space to be exceeded.
89  */
uwb_rc_send_all_drp_ie(struct uwb_rc * rc)90 int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
91 {
92 	int result;
93 	struct uwb_rc_cmd_set_drp_ie *cmd;
94 	struct uwb_rsv *rsv;
95 	struct uwb_rsv_move *mv;
96 	int num_bytes = 0;
97 	u8 *IEDataptr;
98 
99 	result = -ENOMEM;
100 	/* First traverse all reservations to determine memory needed. */
101 	list_for_each_entry(rsv, &rc->reservations, rc_node) {
102 		if (rsv->drp_ie != NULL) {
103 			num_bytes += rsv->drp_ie->hdr.length + 2;
104 			if (uwb_rsv_has_two_drp_ies(rsv) &&
105 				(rsv->mv.companion_drp_ie != NULL)) {
106 				mv = &rsv->mv;
107 				num_bytes +=
108 					mv->companion_drp_ie->hdr.length + 2;
109 			}
110 		}
111 	}
112 	num_bytes += sizeof(rc->drp_avail.ie);
113 	cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
114 	if (cmd == NULL)
115 		goto error;
116 	cmd->rccb.bCommandType = UWB_RC_CET_GENERAL;
117 	cmd->rccb.wCommand = cpu_to_le16(UWB_RC_CMD_SET_DRP_IE);
118 	cmd->wIELength = num_bytes;
119 	IEDataptr = (u8 *)&cmd->IEData[0];
120 
121 	/* FIXME: DRV avail IE is not always needed */
122 	/* put DRP avail IE first */
123 	memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
124 	IEDataptr += sizeof(struct uwb_ie_drp_avail);
125 
126 	/* Next traverse all reservations to place IEs in allocated memory. */
127 	list_for_each_entry(rsv, &rc->reservations, rc_node) {
128 		if (rsv->drp_ie != NULL) {
129 			memcpy(IEDataptr, rsv->drp_ie,
130 			       rsv->drp_ie->hdr.length + 2);
131 			IEDataptr += rsv->drp_ie->hdr.length + 2;
132 
133 			if (uwb_rsv_has_two_drp_ies(rsv) &&
134 				(rsv->mv.companion_drp_ie != NULL)) {
135 				mv = &rsv->mv;
136 				memcpy(IEDataptr, mv->companion_drp_ie,
137 				       mv->companion_drp_ie->hdr.length + 2);
138 				IEDataptr +=
139 					mv->companion_drp_ie->hdr.length + 2;
140 			}
141 		}
142 	}
143 
144 	result = uwb_rc_cmd_async(rc, "SET-DRP-IE",
145 				&cmd->rccb, sizeof(*cmd) + num_bytes,
146 				UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
147 				uwb_rc_set_drp_cmd_done, NULL);
148 
149 	rc->set_drp_ie_pending = 1;
150 
151 	kfree(cmd);
152 error:
153 	return result;
154 }
155 
156 /*
157  * Evaluate the action to perform using conflict resolution rules
158  *
159  * Return a uwb_drp_conflict_action.
160  */
evaluate_conflict_action(struct uwb_ie_drp * ext_drp_ie,int ext_beacon_slot,struct uwb_rsv * rsv,int our_status)161 static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
162 				    struct uwb_rsv *rsv, int our_status)
163 {
164 	int our_tie_breaker = rsv->tiebreaker;
165 	int our_type        = rsv->type;
166 	int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
167 
168 	int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
169 	int ext_status      = uwb_ie_drp_status(ext_drp_ie);
170 	int ext_type        = uwb_ie_drp_type(ext_drp_ie);
171 
172 
173 	/* [ECMA-368 2nd Edition] 17.4.6 */
174 	if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
175 		return UWB_DRP_CONFLICT_MANTAIN;
176 	}
177 
178 	/* [ECMA-368 2nd Edition] 17.4.6-1 */
179 	if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
180 		return UWB_DRP_CONFLICT_MANTAIN;
181 	}
182 
183 	/* [ECMA-368 2nd Edition] 17.4.6-2 */
184 	if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
185 		/* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
186 		return UWB_DRP_CONFLICT_ACT1;
187 	}
188 
189 	/* [ECMA-368 2nd Edition] 17.4.6-3 */
190 	if (our_status == 0 && ext_status == 1) {
191 		return UWB_DRP_CONFLICT_ACT2;
192 	}
193 
194 	/* [ECMA-368 2nd Edition] 17.4.6-4 */
195 	if (our_status == 1 && ext_status == 0) {
196 		return UWB_DRP_CONFLICT_MANTAIN;
197 	}
198 
199 	/* [ECMA-368 2nd Edition] 17.4.6-5a */
200 	if (our_tie_breaker == ext_tie_breaker &&
201 	    our_beacon_slot <  ext_beacon_slot) {
202 		return UWB_DRP_CONFLICT_MANTAIN;
203 	}
204 
205 	/* [ECMA-368 2nd Edition] 17.4.6-5b */
206 	if (our_tie_breaker != ext_tie_breaker &&
207 	    our_beacon_slot >  ext_beacon_slot) {
208 		return UWB_DRP_CONFLICT_MANTAIN;
209 	}
210 
211 	if (our_status == 0) {
212 		if (our_tie_breaker == ext_tie_breaker) {
213 			/* [ECMA-368 2nd Edition] 17.4.6-6a */
214 			if (our_beacon_slot > ext_beacon_slot) {
215 				return UWB_DRP_CONFLICT_ACT2;
216 			}
217 		} else  {
218 			/* [ECMA-368 2nd Edition] 17.4.6-6b */
219 			if (our_beacon_slot < ext_beacon_slot) {
220 				return UWB_DRP_CONFLICT_ACT2;
221 			}
222 		}
223 	} else {
224 		if (our_tie_breaker == ext_tie_breaker) {
225 			/* [ECMA-368 2nd Edition] 17.4.6-7a */
226 			if (our_beacon_slot > ext_beacon_slot) {
227 				return UWB_DRP_CONFLICT_ACT3;
228 			}
229 		} else {
230 			/* [ECMA-368 2nd Edition] 17.4.6-7b */
231 			if (our_beacon_slot < ext_beacon_slot) {
232 				return UWB_DRP_CONFLICT_ACT3;
233 			}
234 		}
235 	}
236 	return UWB_DRP_CONFLICT_MANTAIN;
237 }
238 
handle_conflict_normal(struct uwb_ie_drp * drp_ie,int ext_beacon_slot,struct uwb_rsv * rsv,struct uwb_mas_bm * conflicting_mas)239 static void handle_conflict_normal(struct uwb_ie_drp *drp_ie,
240 				   int ext_beacon_slot,
241 				   struct uwb_rsv *rsv,
242 				   struct uwb_mas_bm *conflicting_mas)
243 {
244 	struct uwb_rc *rc = rsv->rc;
245 	struct uwb_rsv_move *mv = &rsv->mv;
246 	struct uwb_drp_backoff_win *bow = &rc->bow;
247 	int action;
248 
249 	action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
250 
251 	if (uwb_rsv_is_owner(rsv)) {
252 		switch(action) {
253 		case UWB_DRP_CONFLICT_ACT2:
254 			/* try move */
255 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
256 			if (bow->can_reserve_extra_mases == false)
257 				uwb_rsv_backoff_win_increment(rc);
258 
259 			break;
260 		case UWB_DRP_CONFLICT_ACT3:
261 			uwb_rsv_backoff_win_increment(rc);
262 			/* drop some mases with reason modified */
263 			/* put in the companion the mases to be dropped */
264 			bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
265 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
266 		default:
267 			break;
268 		}
269 	} else {
270 		switch(action) {
271 		case UWB_DRP_CONFLICT_ACT2:
272 		case UWB_DRP_CONFLICT_ACT3:
273 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
274 		default:
275 			break;
276 		}
277 
278 	}
279 
280 }
281 
handle_conflict_expanding(struct uwb_ie_drp * drp_ie,int ext_beacon_slot,struct uwb_rsv * rsv,bool companion_only,struct uwb_mas_bm * conflicting_mas)282 static void handle_conflict_expanding(struct uwb_ie_drp *drp_ie, int ext_beacon_slot,
283 				      struct uwb_rsv *rsv, bool companion_only,
284 				      struct uwb_mas_bm *conflicting_mas)
285 {
286 	struct uwb_rc *rc = rsv->rc;
287 	struct uwb_drp_backoff_win *bow = &rc->bow;
288 	struct uwb_rsv_move *mv = &rsv->mv;
289 	int action;
290 
291 	if (companion_only) {
292 		/* status of companion is 0 at this point */
293 		action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
294 		if (uwb_rsv_is_owner(rsv)) {
295 			switch(action) {
296 			case UWB_DRP_CONFLICT_ACT2:
297 			case UWB_DRP_CONFLICT_ACT3:
298 				uwb_rsv_set_state(rsv,
299 						UWB_RSV_STATE_O_ESTABLISHED);
300 				rsv->needs_release_companion_mas = false;
301 				if (bow->can_reserve_extra_mases == false)
302 					uwb_rsv_backoff_win_increment(rc);
303 				uwb_drp_avail_release(rsv->rc,
304 						&rsv->mv.companion_mas);
305 			}
306 		} else { /* rsv is target */
307 			switch(action) {
308 			case UWB_DRP_CONFLICT_ACT2:
309 			case UWB_DRP_CONFLICT_ACT3:
310 				uwb_rsv_set_state(rsv,
311 					UWB_RSV_STATE_T_EXPANDING_CONFLICT);
312                                 /* send_drp_avail_ie = true; */
313 			}
314 		}
315 	} else { /* also base part of the reservation is conflicting */
316 		if (uwb_rsv_is_owner(rsv)) {
317 			uwb_rsv_backoff_win_increment(rc);
318 			/* remove companion part */
319 			uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
320 
321 			/* drop some mases with reason modified */
322 
323 			/* put in the companion the mases to be dropped */
324 			bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm,
325 					conflicting_mas->bm, UWB_NUM_MAS);
326 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
327 		} else { /* it is a target rsv */
328 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
329                         /* send_drp_avail_ie = true; */
330 		}
331 	}
332 }
333 
uwb_drp_handle_conflict_rsv(struct uwb_rc * rc,struct uwb_rsv * rsv,struct uwb_rc_evt_drp * drp_evt,struct uwb_ie_drp * drp_ie,struct uwb_mas_bm * conflicting_mas)334 static void uwb_drp_handle_conflict_rsv(struct uwb_rc *rc, struct uwb_rsv *rsv,
335 					struct uwb_rc_evt_drp *drp_evt,
336 					struct uwb_ie_drp *drp_ie,
337 					struct uwb_mas_bm *conflicting_mas)
338 {
339 	struct uwb_rsv_move *mv;
340 
341 	/* check if the conflicting reservation has two drp_ies */
342 	if (uwb_rsv_has_two_drp_ies(rsv)) {
343 		mv = &rsv->mv;
344 		if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
345 								UWB_NUM_MAS)) {
346 			handle_conflict_expanding(drp_ie,
347 						drp_evt->beacon_slot_number,
348 						rsv, false, conflicting_mas);
349 		} else {
350 			if (bitmap_intersects(mv->companion_mas.bm,
351 					conflicting_mas->bm, UWB_NUM_MAS)) {
352 				handle_conflict_expanding(
353 					drp_ie, drp_evt->beacon_slot_number,
354 					rsv, true, conflicting_mas);
355 			}
356 		}
357 	} else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm,
358 							UWB_NUM_MAS)) {
359 		handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number,
360 					rsv, conflicting_mas);
361 	}
362 }
363 
uwb_drp_handle_all_conflict_rsv(struct uwb_rc * rc,struct uwb_rc_evt_drp * drp_evt,struct uwb_ie_drp * drp_ie,struct uwb_mas_bm * conflicting_mas)364 static void uwb_drp_handle_all_conflict_rsv(struct uwb_rc *rc,
365 					    struct uwb_rc_evt_drp *drp_evt,
366 					    struct uwb_ie_drp *drp_ie,
367 					    struct uwb_mas_bm *conflicting_mas)
368 {
369 	struct uwb_rsv *rsv;
370 
371 	list_for_each_entry(rsv, &rc->reservations, rc_node) {
372 		uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie,
373 							conflicting_mas);
374 	}
375 }
376 
uwb_drp_process_target_accepted(struct uwb_rc * rc,struct uwb_rsv * rsv,struct uwb_rc_evt_drp * drp_evt,struct uwb_ie_drp * drp_ie,struct uwb_mas_bm * mas)377 static void uwb_drp_process_target_accepted(struct uwb_rc *rc,
378 	struct uwb_rsv *rsv, struct uwb_rc_evt_drp *drp_evt,
379 	struct uwb_ie_drp *drp_ie, struct uwb_mas_bm *mas)
380 {
381 	struct uwb_rsv_move *mv = &rsv->mv;
382 	int status;
383 
384 	status = uwb_ie_drp_status(drp_ie);
385 
386 	if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
387 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
388 		return;
389 	}
390 
391 	if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
392 		/* drp_ie is companion */
393 		if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
394 			/* stroke companion */
395 			uwb_rsv_set_state(rsv,
396 				UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
397 		}
398 	} else {
399 		if (!bitmap_equal(rsv->mas.bm, mas->bm, UWB_NUM_MAS)) {
400 			if (uwb_drp_avail_reserve_pending(rc, mas) == -EBUSY) {
401 				/* FIXME: there is a conflict, find
402 				 * the conflicting reservations and
403 				 * take a sensible action. Consider
404 				 * that in drp_ie there is the
405 				 * "neighbour" */
406 				uwb_drp_handle_all_conflict_rsv(rc, drp_evt,
407 						drp_ie, mas);
408 			} else {
409 				/* accept the extra reservation */
410 				bitmap_copy(mv->companion_mas.bm, mas->bm,
411 								UWB_NUM_MAS);
412 				uwb_rsv_set_state(rsv,
413 					UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
414 			}
415 		} else {
416 			if (status) {
417 				uwb_rsv_set_state(rsv,
418 						UWB_RSV_STATE_T_ACCEPTED);
419 			}
420 		}
421 
422 	}
423 }
424 
425 /*
426  * Based on the DRP IE, transition a target reservation to a new
427  * state.
428  */
uwb_drp_process_target(struct uwb_rc * rc,struct uwb_rsv * rsv,struct uwb_ie_drp * drp_ie,struct uwb_rc_evt_drp * drp_evt)429 static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
430 		   struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
431 {
432 	struct device *dev = &rc->uwb_dev.dev;
433 	struct uwb_rsv_move *mv = &rsv->mv;
434 	int status;
435 	enum uwb_drp_reason reason_code;
436 	struct uwb_mas_bm mas;
437 
438 	status = uwb_ie_drp_status(drp_ie);
439 	reason_code = uwb_ie_drp_reason_code(drp_ie);
440 	uwb_drp_ie_to_bm(&mas, drp_ie);
441 
442 	switch (reason_code) {
443 	case UWB_DRP_REASON_ACCEPTED:
444 		uwb_drp_process_target_accepted(rc, rsv, drp_evt, drp_ie, &mas);
445 		break;
446 
447 	case UWB_DRP_REASON_MODIFIED:
448 		/* check to see if we have already modified the reservation */
449 		if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
450 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
451 			break;
452 		}
453 
454 		/* find if the owner wants to expand or reduce */
455 		if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
456 			/* owner is reducing */
457 			bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm,
458 				UWB_NUM_MAS);
459 			uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
460 		}
461 
462 		bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
463 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
464 		break;
465 	default:
466 		dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
467 			 reason_code, status);
468 	}
469 }
470 
uwb_drp_process_owner_accepted(struct uwb_rsv * rsv,struct uwb_mas_bm * mas)471 static void uwb_drp_process_owner_accepted(struct uwb_rsv *rsv,
472 						struct uwb_mas_bm *mas)
473 {
474 	struct uwb_rsv_move *mv = &rsv->mv;
475 
476 	switch (rsv->state) {
477 	case UWB_RSV_STATE_O_PENDING:
478 	case UWB_RSV_STATE_O_INITIATED:
479 	case UWB_RSV_STATE_O_ESTABLISHED:
480 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
481 		break;
482 	case UWB_RSV_STATE_O_MODIFIED:
483 		if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
484 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
485 		else
486 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
487 		break;
488 
489 	case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
490 		if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
491 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
492 		else
493 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
494 		break;
495 	case UWB_RSV_STATE_O_MOVE_EXPANDING:
496 		if (bitmap_equal(mas->bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
497 			/* Companion reservation accepted */
498 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
499 		} else {
500 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
501 		}
502 		break;
503 	case UWB_RSV_STATE_O_MOVE_COMBINING:
504 		if (bitmap_equal(mas->bm, rsv->mas.bm, UWB_NUM_MAS))
505 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
506 		else
507 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
508 		break;
509 	default:
510 		break;
511 	}
512 }
513 /*
514  * Based on the DRP IE, transition an owner reservation to a new
515  * state.
516  */
uwb_drp_process_owner(struct uwb_rc * rc,struct uwb_rsv * rsv,struct uwb_dev * src,struct uwb_ie_drp * drp_ie,struct uwb_rc_evt_drp * drp_evt)517 static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
518 				  struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
519 				  struct uwb_rc_evt_drp *drp_evt)
520 {
521 	struct device *dev = &rc->uwb_dev.dev;
522 	int status;
523 	enum uwb_drp_reason reason_code;
524 	struct uwb_mas_bm mas;
525 
526 	status = uwb_ie_drp_status(drp_ie);
527 	reason_code = uwb_ie_drp_reason_code(drp_ie);
528 	uwb_drp_ie_to_bm(&mas, drp_ie);
529 
530 	if (status) {
531 		switch (reason_code) {
532 		case UWB_DRP_REASON_ACCEPTED:
533 			uwb_drp_process_owner_accepted(rsv, &mas);
534 			break;
535 		default:
536 			dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
537 				 reason_code, status);
538 		}
539 	} else {
540 		switch (reason_code) {
541 		case UWB_DRP_REASON_PENDING:
542 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_PENDING);
543 			break;
544 		case UWB_DRP_REASON_DENIED:
545 			uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
546 			break;
547 		case UWB_DRP_REASON_CONFLICT:
548 			/* resolve the conflict */
549 			bitmap_complement(mas.bm, src->last_availability_bm,
550 					  UWB_NUM_MAS);
551 			uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
552 			break;
553 		default:
554 			dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
555 				 reason_code, status);
556 		}
557 	}
558 }
559 
uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien * cnflt)560 static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
561 {
562 	unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
563 	mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
564 }
565 
uwb_cnflt_update_work(struct work_struct * work)566 static void uwb_cnflt_update_work(struct work_struct *work)
567 {
568 	struct uwb_cnflt_alien *cnflt = container_of(work,
569 						     struct uwb_cnflt_alien,
570 						     cnflt_update_work);
571 	struct uwb_cnflt_alien *c;
572 	struct uwb_rc *rc = cnflt->rc;
573 
574 	unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
575 
576 	mutex_lock(&rc->rsvs_mutex);
577 
578 	list_del(&cnflt->rc_node);
579 
580 	/* update rc global conflicting alien bitmap */
581 	bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
582 
583 	list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
584 		bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm,
585 						c->mas.bm, UWB_NUM_MAS);
586 	}
587 
588 	queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work,
589 					usecs_to_jiffies(delay_us));
590 
591 	kfree(cnflt);
592 	mutex_unlock(&rc->rsvs_mutex);
593 }
594 
uwb_cnflt_timer(struct timer_list * t)595 static void uwb_cnflt_timer(struct timer_list *t)
596 {
597 	struct uwb_cnflt_alien *cnflt = from_timer(cnflt, t, timer);
598 
599 	queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
600 }
601 
602 /*
603  * We have received an DRP_IE of type Alien BP and we need to make
604  * sure we do not transmit in conflicting MASs.
605  */
uwb_drp_handle_alien_drp(struct uwb_rc * rc,struct uwb_ie_drp * drp_ie)606 static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
607 {
608 	struct device *dev = &rc->uwb_dev.dev;
609 	struct uwb_mas_bm mas;
610 	struct uwb_cnflt_alien *cnflt;
611 	unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
612 
613 	uwb_drp_ie_to_bm(&mas, drp_ie);
614 
615 	list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
616 		if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
617 			/* Existing alien BP reservation conflicting
618 			 * bitmap, just reset the timer */
619 			uwb_cnflt_alien_stroke_timer(cnflt);
620 			return;
621 		}
622 	}
623 
624 	/* New alien BP reservation conflicting bitmap */
625 
626 	/* alloc and initialize new uwb_cnflt_alien */
627 	cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
628 	if (!cnflt) {
629 		dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
630 		return;
631 	}
632 
633 	INIT_LIST_HEAD(&cnflt->rc_node);
634 	timer_setup(&cnflt->timer, uwb_cnflt_timer, 0);
635 
636 	cnflt->rc = rc;
637 	INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
638 
639 	bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
640 
641 	list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
642 
643 	/* update rc global conflicting alien bitmap */
644 	bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
645 
646 	queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
647 
648 	/* start the timer */
649 	uwb_cnflt_alien_stroke_timer(cnflt);
650 }
651 
uwb_drp_process_not_involved(struct uwb_rc * rc,struct uwb_rc_evt_drp * drp_evt,struct uwb_ie_drp * drp_ie)652 static void uwb_drp_process_not_involved(struct uwb_rc *rc,
653 					 struct uwb_rc_evt_drp *drp_evt,
654 					 struct uwb_ie_drp *drp_ie)
655 {
656 	struct uwb_mas_bm mas;
657 
658 	uwb_drp_ie_to_bm(&mas, drp_ie);
659 	uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
660 }
661 
uwb_drp_process_involved(struct uwb_rc * rc,struct uwb_dev * src,struct uwb_rc_evt_drp * drp_evt,struct uwb_ie_drp * drp_ie)662 static void uwb_drp_process_involved(struct uwb_rc *rc, struct uwb_dev *src,
663 				     struct uwb_rc_evt_drp *drp_evt,
664 				     struct uwb_ie_drp *drp_ie)
665 {
666 	struct uwb_rsv *rsv;
667 
668 	rsv = uwb_rsv_find(rc, src, drp_ie);
669 	if (!rsv) {
670 		/*
671 		 * No reservation? It's either for a recently
672 		 * terminated reservation; or the DRP IE couldn't be
673 		 * processed (e.g., an invalid IE or out of memory).
674 		 */
675 		return;
676 	}
677 
678 	/*
679 	 * Do nothing with DRP IEs for reservations that have been
680 	 * terminated.
681 	 */
682 	if (rsv->state == UWB_RSV_STATE_NONE) {
683 		uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
684 		return;
685 	}
686 
687 	if (uwb_ie_drp_owner(drp_ie))
688 		uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
689 	else
690 		uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
691 
692 }
693 
694 
uwb_drp_involves_us(struct uwb_rc * rc,struct uwb_ie_drp * drp_ie)695 static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
696 {
697 	return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
698 }
699 
700 /*
701  * Process a received DRP IE.
702  */
uwb_drp_process(struct uwb_rc * rc,struct uwb_rc_evt_drp * drp_evt,struct uwb_dev * src,struct uwb_ie_drp * drp_ie)703 static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
704 			    struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
705 {
706 	if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
707 		uwb_drp_handle_alien_drp(rc, drp_ie);
708 	else if (uwb_drp_involves_us(rc, drp_ie))
709 		uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
710 	else
711 		uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
712 }
713 
714 /*
715  * Process a received DRP Availability IE
716  */
uwb_drp_availability_process(struct uwb_rc * rc,struct uwb_dev * src,struct uwb_ie_drp_avail * drp_availability_ie)717 static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
718 					 struct uwb_ie_drp_avail *drp_availability_ie)
719 {
720 	bitmap_copy(src->last_availability_bm,
721 		    drp_availability_ie->bmp, UWB_NUM_MAS);
722 }
723 
724 /*
725  * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
726  * from a device.
727  */
728 static
uwb_drp_process_all(struct uwb_rc * rc,struct uwb_rc_evt_drp * drp_evt,size_t ielen,struct uwb_dev * src_dev)729 void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
730 			 size_t ielen, struct uwb_dev *src_dev)
731 {
732 	struct device *dev = &rc->uwb_dev.dev;
733 	struct uwb_ie_hdr *ie_hdr;
734 	void *ptr;
735 
736 	ptr = drp_evt->ie_data;
737 	for (;;) {
738 		ie_hdr = uwb_ie_next(&ptr, &ielen);
739 		if (!ie_hdr)
740 			break;
741 
742 		switch (ie_hdr->element_id) {
743 		case UWB_IE_DRP_AVAILABILITY:
744 			uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
745 			break;
746 		case UWB_IE_DRP:
747 			uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
748 			break;
749 		default:
750 			dev_warn(dev, "unexpected IE in DRP notification\n");
751 			break;
752 		}
753 	}
754 
755 	if (ielen > 0)
756 		dev_warn(dev, "%d octets remaining in DRP notification\n",
757 			 (int)ielen);
758 }
759 
760 /**
761  * uwbd_evt_handle_rc_drp - handle a DRP_IE event
762  * @evt: the DRP_IE event from the radio controller
763  *
764  * This processes DRP notifications from the radio controller, either
765  * initiating a new reservation or transitioning an existing
766  * reservation into a different state.
767  *
768  * DRP notifications can occur for three different reasons:
769  *
770  * - UWB_DRP_NOTIF_DRP_IE_RECVD: one or more DRP IEs with the RC as
771  *   the target or source have been received.
772  *
773  *   These DRP IEs could be new or for an existing reservation.
774  *
775  *   If the DRP IE for an existing reservation ceases to be to
776  *   received for at least mMaxLostBeacons, the reservation should be
777  *   considered to be terminated.  Note that the TERMINATE reason (see
778  *   below) may not always be signalled (e.g., the remote device has
779  *   two or more reservations established with the RC).
780  *
781  * - UWB_DRP_NOTIF_CONFLICT: DRP IEs from any device in the beacon
782  *   group conflict with the RC's reservations.
783  *
784  * - UWB_DRP_NOTIF_TERMINATE: DRP IEs are no longer being received
785  *   from a device (i.e., it's terminated all reservations).
786  *
787  * Only the software state of the reservations is changed; the setting
788  * of the radio controller's DRP IEs is done after all the events in
789  * an event buffer are processed.  This saves waiting multiple times
790  * for the SET_DRP_IE command to complete.
791  */
uwbd_evt_handle_rc_drp(struct uwb_event * evt)792 int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
793 {
794 	struct device *dev = &evt->rc->uwb_dev.dev;
795 	struct uwb_rc *rc = evt->rc;
796 	struct uwb_rc_evt_drp *drp_evt;
797 	size_t ielength, bytes_left;
798 	struct uwb_dev_addr src_addr;
799 	struct uwb_dev *src_dev;
800 
801 	/* Is there enough data to decode the event (and any IEs in
802 	   its payload)? */
803 	if (evt->notif.size < sizeof(*drp_evt)) {
804 		dev_err(dev, "DRP event: Not enough data to decode event "
805 			"[%zu bytes left, %zu needed]\n",
806 			evt->notif.size, sizeof(*drp_evt));
807 		return 0;
808 	}
809 	bytes_left = evt->notif.size - sizeof(*drp_evt);
810 	drp_evt = container_of(evt->notif.rceb, struct uwb_rc_evt_drp, rceb);
811 	ielength = le16_to_cpu(drp_evt->ie_length);
812 	if (bytes_left != ielength) {
813 		dev_err(dev, "DRP event: Not enough data in payload [%zu"
814 			"bytes left, %zu declared in the event]\n",
815 			bytes_left, ielength);
816 		return 0;
817 	}
818 
819 	memcpy(src_addr.data, &drp_evt->src_addr, sizeof(src_addr));
820 	src_dev = uwb_dev_get_by_devaddr(rc, &src_addr);
821 	if (!src_dev) {
822 		/*
823 		 * A DRP notification from an unrecognized device.
824 		 *
825 		 * This is probably from a WUSB device that doesn't
826 		 * have an EUI-48 and therefore doesn't show up in the
827 		 * UWB device database.  It's safe to simply ignore
828 		 * these.
829 		 */
830 		return 0;
831 	}
832 
833 	mutex_lock(&rc->rsvs_mutex);
834 
835 	/* We do not distinguish from the reason */
836 	uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
837 
838 	mutex_unlock(&rc->rsvs_mutex);
839 
840 	uwb_dev_put(src_dev);
841 	return 0;
842 }
843