ata_piix: Add HP Compaq nc6000 to the broken poweroff list
[safe/jmp/linux-2.6] / drivers / uwb / drp.c
index fe32814..4f5ca99 100644 (file)
 #include <linux/delay.h>
 #include "uwb-internal.h"
 
+
+/* DRP Conflict Actions ([ECMA-368 2nd Edition] 17.4.6) */
+enum uwb_drp_conflict_action {
+       /* Reservation is mantained, no action needed */
+       UWB_DRP_CONFLICT_MANTAIN = 0,
+       
+       /* the device shall not transmit frames in conflicting MASs in
+        * the following superframe. If the device is the reservation
+        * target, it shall also set the Reason Code in its DRP IE to
+        * Conflict in its beacon in the following superframe.
+        */
+       UWB_DRP_CONFLICT_ACT1,
+       
+       /* the device shall not set the Reservation Status bit to ONE
+        * and shall not transmit frames in conflicting MASs. If the
+        * device is the reservation target, it shall also set the
+        * Reason Code in its DRP IE to Conflict.
+        */     
+       UWB_DRP_CONFLICT_ACT2,
+
+       /* the device shall not transmit frames in conflicting MASs in
+        * the following superframe. It shall remove the conflicting
+        * MASs from the reservation or set the Reservation Status to
+        * ZERO in its beacon in the following superframe. If the
+        * device is the reservation target, it shall also set the
+        * Reason Code in its DRP IE to Conflict.
+        */
+       UWB_DRP_CONFLICT_ACT3,
+};
+
+
+static void uwb_rc_set_drp_cmd_done(struct uwb_rc *rc, void *arg,
+                                   struct uwb_rceb *reply, ssize_t reply_size)
+{
+       struct uwb_rc_evt_set_drp_ie *r = (struct uwb_rc_evt_set_drp_ie *)reply;
+
+       if (r != NULL) {
+               if (r->bResultCode != UWB_RC_RES_SUCCESS)
+                       dev_err(&rc->uwb_dev.dev, "SET-DRP-IE failed: %s (%d)\n",
+                               uwb_rc_strerror(r->bResultCode), r->bResultCode);
+       } else
+               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: timeout\n");
+
+       spin_lock_bh(&rc->rsvs_lock);
+       if (rc->set_drp_ie_pending > 1) {
+               rc->set_drp_ie_pending = 0;
+               uwb_rsv_queue_update(rc);       
+       } else {
+               rc->set_drp_ie_pending = 0;     
+       }
+       spin_unlock_bh(&rc->rsvs_lock);
+}
+
 /**
  * Construct and send the SET DRP IE
  *
 int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
 {
        int result;
-       struct device *dev = &rc->uwb_dev.dev;
        struct uwb_rc_cmd_set_drp_ie *cmd;
-       struct uwb_rc_evt_set_drp_ie reply;
        struct uwb_rsv *rsv;
+       struct uwb_rsv_move *mv;
        int num_bytes = 0;
        u8 *IEDataptr;
 
        result = -ENOMEM;
        /* First traverse all reservations to determine memory needed. */
        list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->drp_ie != NULL)
+               if (rsv->drp_ie != NULL) {
                        num_bytes += rsv->drp_ie->hdr.length + 2;
+                       if (uwb_rsv_has_two_drp_ies(rsv) &&
+                               (rsv->mv.companion_drp_ie != NULL)) {
+                               mv = &rsv->mv;
+                               num_bytes += mv->companion_drp_ie->hdr.length + 2;      
+                       }
+               }
        }
        num_bytes += sizeof(rc->drp_avail.ie);
        cmd = kzalloc(sizeof(*cmd) + num_bytes, GFP_KERNEL);
@@ -68,109 +126,322 @@ int uwb_rc_send_all_drp_ie(struct uwb_rc *rc)
        cmd->wIELength = num_bytes;
        IEDataptr = (u8 *)&cmd->IEData[0];
 
+       /* FIXME: DRV avail IE is not always needed */
+       /* put DRP avail IE first */
+       memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
+       IEDataptr += sizeof(struct uwb_ie_drp_avail);
+
        /* Next traverse all reservations to place IEs in allocated memory. */
        list_for_each_entry(rsv, &rc->reservations, rc_node) {
                if (rsv->drp_ie != NULL) {
                        memcpy(IEDataptr, rsv->drp_ie,
                               rsv->drp_ie->hdr.length + 2);
                        IEDataptr += rsv->drp_ie->hdr.length + 2;
+                       
+                       if (uwb_rsv_has_two_drp_ies(rsv) &&
+                               (rsv->mv.companion_drp_ie != NULL)) {
+                               mv = &rsv->mv;
+                               memcpy(IEDataptr, mv->companion_drp_ie,
+                                      mv->companion_drp_ie->hdr.length + 2);
+                               IEDataptr += mv->companion_drp_ie->hdr.length + 2;      
+                       }
                }
        }
-       memcpy(IEDataptr, &rc->drp_avail.ie, sizeof(rc->drp_avail.ie));
 
-       reply.rceb.bEventType = UWB_RC_CET_GENERAL;
-       reply.rceb.wEvent = UWB_RC_CMD_SET_DRP_IE;
-       result = uwb_rc_cmd(rc, "SET-DRP-IE", &cmd->rccb,
-                       sizeof(*cmd) + num_bytes, &reply.rceb,
-                       sizeof(reply));
-       if (result < 0)
-               goto error_cmd;
-       result = le16_to_cpu(reply.wRemainingSpace);
-       if (reply.bResultCode != UWB_RC_RES_SUCCESS) {
-               dev_err(&rc->uwb_dev.dev, "SET-DRP-IE: command execution "
-                               "failed: %s (%d). RemainingSpace in beacon "
-                               "= %d\n", uwb_rc_strerror(reply.bResultCode),
-                               reply.bResultCode, result);
-               result = -EIO;
-       } else {
-               dev_dbg(dev, "SET-DRP-IE sent. RemainingSpace in beacon "
-                            "= %d.\n", result);
-               result = 0;
-       }
-error_cmd:
+       result = uwb_rc_cmd_async(rc, "SET-DRP-IE", &cmd->rccb, sizeof(*cmd) + num_bytes,
+                                 UWB_RC_CET_GENERAL, UWB_RC_CMD_SET_DRP_IE,
+                                 uwb_rc_set_drp_cmd_done, NULL);
+       
+       rc->set_drp_ie_pending = 1;
+
        kfree(cmd);
 error:
        return result;
 }
 
-void uwb_drp_handle_timeout(struct uwb_rsv *rsv)
+/*
+ * Evaluate the action to perform using conflict resolution rules
+ *
+ * Return a uwb_drp_conflict_action.
+ */
+static int evaluate_conflict_action(struct uwb_ie_drp *ext_drp_ie, int ext_beacon_slot,
+                                   struct uwb_rsv *rsv, int our_status)
 {
-       struct device *dev = &rsv->rc->uwb_dev.dev;
+       int our_tie_breaker = rsv->tiebreaker;
+       int our_type        = rsv->type;
+       int our_beacon_slot = rsv->rc->uwb_dev.beacon_slot;
+
+       int ext_tie_breaker = uwb_ie_drp_tiebreaker(ext_drp_ie);
+       int ext_status      = uwb_ie_drp_status(ext_drp_ie);
+       int ext_type        = uwb_ie_drp_type(ext_drp_ie);
+       
+       
+       /* [ECMA-368 2nd Edition] 17.4.6 */
+       if (ext_type == UWB_DRP_TYPE_PCA && our_type == UWB_DRP_TYPE_PCA) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-1 */
+       if (our_type == UWB_DRP_TYPE_ALIEN_BP) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+       
+       /* [ECMA-368 2nd Edition] 17.4.6-2 */
+       if (ext_type == UWB_DRP_TYPE_ALIEN_BP) {
+               /* here we know our_type != UWB_DRP_TYPE_ALIEN_BP */
+               return UWB_DRP_CONFLICT_ACT1;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-3 */
+       if (our_status == 0 && ext_status == 1) {
+               return UWB_DRP_CONFLICT_ACT2;
+       }
 
-       dev_dbg(dev, "reservation timeout in state %s (%d)\n",
-               uwb_rsv_state_str(rsv->state), rsv->state);
+       /* [ECMA-368 2nd Edition] 17.4.6-4 */
+       if (our_status == 1 && ext_status == 0) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
 
-       switch (rsv->state) {
-       case UWB_RSV_STATE_O_INITIATED:
-               if (rsv->is_multicast) {
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       return;
+       /* [ECMA-368 2nd Edition] 17.4.6-5a */
+       if (our_tie_breaker == ext_tie_breaker &&
+           our_beacon_slot <  ext_beacon_slot) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+
+       /* [ECMA-368 2nd Edition] 17.4.6-5b */
+       if (our_tie_breaker != ext_tie_breaker &&
+           our_beacon_slot >  ext_beacon_slot) {
+               return UWB_DRP_CONFLICT_MANTAIN;
+       }
+       
+       if (our_status == 0) {
+               if (our_tie_breaker == ext_tie_breaker) {
+                       /* [ECMA-368 2nd Edition] 17.4.6-6a */
+                       if (our_beacon_slot > ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT2;
+                       }
+               } else  {
+                       /* [ECMA-368 2nd Edition] 17.4.6-6b */
+                       if (our_beacon_slot < ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT2;
+                       }
                }
-               break;
-       case UWB_RSV_STATE_O_ESTABLISHED:
-               if (rsv->is_multicast)
-                       return;
-               break;
-       default:
-               break;
+       } else {
+               if (our_tie_breaker == ext_tie_breaker) {
+                       /* [ECMA-368 2nd Edition] 17.4.6-7a */
+                       if (our_beacon_slot > ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT3;
+                       }
+               } else {
+                       /* [ECMA-368 2nd Edition] 17.4.6-7b */
+                       if (our_beacon_slot < ext_beacon_slot) {
+                               return UWB_DRP_CONFLICT_ACT3;
+                       }
+               }
+       }
+       return UWB_DRP_CONFLICT_MANTAIN;
+}
+
+static void handle_conflict_normal(struct uwb_ie_drp *drp_ie, 
+                                  int ext_beacon_slot, 
+                                  struct uwb_rsv *rsv, 
+                                  struct uwb_mas_bm *conflicting_mas)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_rsv_move *mv = &rsv->mv;
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       int action;
+
+       action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, uwb_rsv_status(rsv));
+
+       if (uwb_rsv_is_owner(rsv)) {
+               switch(action) {
+               case UWB_DRP_CONFLICT_ACT2:
+                       /* try move */
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_TO_BE_MOVED);
+                       if (bow->can_reserve_extra_mases == false)
+                               uwb_rsv_backoff_win_increment(rc);
+                       
+                       break;
+               case UWB_DRP_CONFLICT_ACT3:
+                       uwb_rsv_backoff_win_increment(rc);
+                       /* drop some mases with reason modified */
+                       /* put in the companion the mases to be dropped */
+                       bitmap_and(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+               default:
+                       break;
+               }
+       } else {
+               switch(action) {
+               case UWB_DRP_CONFLICT_ACT2:
+               case UWB_DRP_CONFLICT_ACT3:
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);       
+               default:
+                       break;
+               }
+
+       }
+       
+}
+
+static void 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)
+{
+       struct uwb_rc *rc = rsv->rc;
+       struct uwb_drp_backoff_win *bow = &rc->bow;
+       struct uwb_rsv_move *mv = &rsv->mv;
+       int action;
+       
+       if (companion_only) {
+               /* status of companion is 0 at this point */
+               action = evaluate_conflict_action(drp_ie, ext_beacon_slot, rsv, 0);
+               if (uwb_rsv_is_owner(rsv)) {
+                       switch(action) {
+                       case UWB_DRP_CONFLICT_ACT2:
+                       case UWB_DRP_CONFLICT_ACT3:
+                               uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                               rsv->needs_release_companion_mas = false;
+                               if (bow->can_reserve_extra_mases == false)
+                                       uwb_rsv_backoff_win_increment(rc);
+                               uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+                       }
+               } else { /* rsv is target */                    
+                       switch(action) {
+                       case UWB_DRP_CONFLICT_ACT2:
+                       case UWB_DRP_CONFLICT_ACT3:
+                               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_CONFLICT);
+                                /* send_drp_avail_ie = true; */
+                       }
+               }
+       } else { /* also base part of the reservation is conflicting */         
+               if (uwb_rsv_is_owner(rsv)) {
+                       uwb_rsv_backoff_win_increment(rc);
+                       /* remove companion part */
+                       uwb_drp_avail_release(rsv->rc, &rsv->mv.companion_mas);
+
+                       /* drop some mases with reason modified */
+
+                       /* put in the companion the mases to be dropped */
+                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS);
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);
+               } else { /* it is a target rsv */
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
+                        /* send_drp_avail_ie = true; */
+               }
+       }
+}
+
+static void 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)
+{
+       struct uwb_rsv_move *mv;
+
+       /* check if the conflicting reservation has two drp_ies */
+       if (uwb_rsv_has_two_drp_ies(rsv)) {
+               mv = &rsv->mv;
+               if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) {
+                       handle_conflict_expanding(drp_ie, drp_evt->beacon_slot_number,
+                                                 rsv, false, conflicting_mas);
+               } else {
+                       if (bitmap_intersects(mv->companion_mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) {
+                               handle_conflict_expanding(drp_ie, drp_evt->beacon_slot_number,
+                                                         rsv, true, conflicting_mas);  
+                       }
+               }
+       } else if (bitmap_intersects(rsv->mas.bm, conflicting_mas->bm, UWB_NUM_MAS)) {
+               handle_conflict_normal(drp_ie, drp_evt->beacon_slot_number, rsv, conflicting_mas);
        }
-       uwb_rsv_remove(rsv);
 }
 
+static void 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)
+{
+       struct uwb_rsv *rsv;
+       
+       list_for_each_entry(rsv, &rc->reservations, rc_node) {
+               uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, conflicting_mas); 
+       }
+}
+       
 /*
  * Based on the DRP IE, transition a target reservation to a new
  * state.
  */
 static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                  struct uwb_ie_drp *drp_ie)
+                                  struct uwb_ie_drp *drp_ie, struct uwb_rc_evt_drp *drp_evt)
 {
        struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rsv_move *mv = &rsv->mv;
        int status;
        enum uwb_drp_reason reason_code;
-
+       struct uwb_mas_bm mas;
+       
        status = uwb_ie_drp_status(drp_ie);
        reason_code = uwb_ie_drp_reason_code(drp_ie);
+       uwb_drp_ie_to_bm(&mas, drp_ie);
 
-       if (status) {
-               switch (reason_code) {
-               case UWB_DRP_REASON_ACCEPTED:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
-                       break;
-               case UWB_DRP_REASON_MODIFIED:
-                       dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
-                               reason_code, status);
+       switch (reason_code) {
+       case UWB_DRP_REASON_ACCEPTED:
+
+               if (rsv->state == UWB_RSV_STATE_T_CONFLICT) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_CONFLICT);
                        break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
                }
-       } else {
-               switch (reason_code) {
-               case UWB_DRP_REASON_ACCEPTED:
-                       /* New reservations are handled in uwb_rsv_find(). */
-                       break;
-               case UWB_DRP_REASON_DENIED:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
-                       break;
-               case UWB_DRP_REASON_CONFLICT:
-               case UWB_DRP_REASON_MODIFIED:
-                       dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
-                               reason_code, status);
+
+               if (rsv->state == UWB_RSV_STATE_T_EXPANDING_ACCEPTED) {
+                       /* drp_ie is companion */
+                       if (!bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS))
+                               /* stroke companion */
+                               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);     
+               } else {
+                       if (!bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
+                               if (uwb_drp_avail_reserve_pending(rc, &mas) == -EBUSY) {
+                                       /* FIXME: there is a conflict, find
+                                        * the conflicting reservations and
+                                        * take a sensible action. Consider
+                                        * that in drp_ie there is the
+                                        * "neighbour" */
+                                       uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
+                               } else {
+                                       /* accept the extra reservation */
+                                       bitmap_copy(mv->companion_mas.bm, mas.bm, UWB_NUM_MAS);
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_EXPANDING_ACCEPTED);
+                               }
+                       } else {
+                               if (status) {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
+                               }
+                       }
+                       
+               }
+               break;
+
+       case UWB_DRP_REASON_MODIFIED:
+               /* check to see if we have already modified the reservation */
+               if (bitmap_equal(rsv->mas.bm, mas.bm, UWB_NUM_MAS)) {
+                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_ACCEPTED);
                        break;
-               default:
-                       dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
-                                reason_code, status);
                }
+
+               /* find if the owner wants to expand or reduce */
+               if (bitmap_subset(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
+                       /* owner is reducing */
+                       bitmap_andnot(mv->companion_mas.bm, rsv->mas.bm, mas.bm, UWB_NUM_MAS);
+                       uwb_drp_avail_release(rsv->rc, &mv->companion_mas);
+               }
+
+               bitmap_copy(rsv->mas.bm, mas.bm, UWB_NUM_MAS);
+               uwb_rsv_set_state(rsv, UWB_RSV_STATE_T_RESIZED);
+               break;
+       default:
+               dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
+                        reason_code, status);
        }
 }
 
@@ -179,23 +450,60 @@ static void uwb_drp_process_target(struct uwb_rc *rc, struct uwb_rsv *rsv,
  * state.
  */
 static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
-                                 struct uwb_ie_drp *drp_ie)
+                                 struct uwb_dev *src, struct uwb_ie_drp *drp_ie,
+                                 struct uwb_rc_evt_drp *drp_evt)
 {
        struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_rsv_move *mv = &rsv->mv;
        int status;
        enum uwb_drp_reason reason_code;
+       struct uwb_mas_bm mas;
 
        status = uwb_ie_drp_status(drp_ie);
        reason_code = uwb_ie_drp_reason_code(drp_ie);
+       uwb_drp_ie_to_bm(&mas, drp_ie);
 
        if (status) {
                switch (reason_code) {
                case UWB_DRP_REASON_ACCEPTED:
-                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
-                       break;
-               case UWB_DRP_REASON_MODIFIED:
-                       dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
-                               reason_code, status);
+                       switch (rsv->state) {
+                       case UWB_RSV_STATE_O_PENDING:
+                       case UWB_RSV_STATE_O_INITIATED:
+                       case UWB_RSV_STATE_O_ESTABLISHED:
+                               uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                               break;
+                       case UWB_RSV_STATE_O_MODIFIED:
+                               if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                               } else {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MODIFIED);       
+                               }
+                               break;
+                               
+                       case UWB_RSV_STATE_O_MOVE_REDUCING: /* shouldn' t be a problem */
+                               if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS)) {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_ESTABLISHED);
+                               } else {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);  
+                               }
+                               break;
+                       case UWB_RSV_STATE_O_MOVE_EXPANDING:
+                               if (bitmap_equal(mas.bm, mv->companion_mas.bm, UWB_NUM_MAS)) {
+                                       /* Companion reservation accepted */
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+                               } else {
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_EXPANDING);
+                               }
+                               break;
+                       case UWB_RSV_STATE_O_MOVE_COMBINING:
+                               if (bitmap_equal(mas.bm, rsv->mas.bm, UWB_NUM_MAS))
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_REDUCING);
+                               else
+                                       uwb_rsv_set_state(rsv, UWB_RSV_STATE_O_MOVE_COMBINING);
+                               break;
+                       default:
+                               break;  
+                       }
                        break;
                default:
                        dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
@@ -210,9 +518,10 @@ static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
                        uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
                        break;
                case UWB_DRP_REASON_CONFLICT:
-               case UWB_DRP_REASON_MODIFIED:
-                       dev_err(dev, "FIXME: unhandled reason code (%d/%d)\n",
-                               reason_code, status);
+                       /* resolve the conflict */
+                       bitmap_complement(mas.bm, src->last_availability_bm,
+                                         UWB_NUM_MAS);
+                       uwb_drp_handle_conflict_rsv(rc, rsv, drp_evt, drp_ie, &mas);
                        break;
                default:
                        dev_warn(dev, "ignoring invalid DRP IE state (%d/%d)\n",
@@ -221,12 +530,110 @@ static void uwb_drp_process_owner(struct uwb_rc *rc, struct uwb_rsv *rsv,
        }
 }
 
+static void uwb_cnflt_alien_stroke_timer(struct uwb_cnflt_alien *cnflt)
+{
+       unsigned timeout_us = UWB_MAX_LOST_BEACONS * UWB_SUPERFRAME_LENGTH_US;
+       mod_timer(&cnflt->timer, jiffies + usecs_to_jiffies(timeout_us));
+}
+
+static void uwb_cnflt_update_work(struct work_struct *work)
+{
+       struct uwb_cnflt_alien *cnflt = container_of(work,
+                                                    struct uwb_cnflt_alien,
+                                                    cnflt_update_work);
+       struct uwb_cnflt_alien *c;
+       struct uwb_rc *rc = cnflt->rc;
+       
+       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+       
+       mutex_lock(&rc->rsvs_mutex);
+
+       list_del(&cnflt->rc_node);
+
+       /* update rc global conflicting alien bitmap */
+       bitmap_zero(rc->cnflt_alien_bitmap.bm, UWB_NUM_MAS);
+
+       list_for_each_entry(c, &rc->cnflt_alien_list, rc_node) {
+               bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, c->mas.bm, UWB_NUM_MAS);                        
+       }
+       
+       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
+
+       kfree(cnflt);
+       mutex_unlock(&rc->rsvs_mutex);
+}
+
+static void uwb_cnflt_timer(unsigned long arg)
+{
+       struct uwb_cnflt_alien *cnflt = (struct uwb_cnflt_alien *)arg;
+
+       queue_work(cnflt->rc->rsv_workq, &cnflt->cnflt_update_work);
+}
+
 /*
- * Process a received DRP IE, it's either for a reservation owned by
- * the RC or targeted at it (or it's for a WUSB cluster reservation).
+ * We have received an DRP_IE of type Alien BP and we need to make
+ * sure we do not transmit in conflicting MASs.
  */
-static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src,
-                    struct uwb_ie_drp *drp_ie)
+static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+       struct device *dev = &rc->uwb_dev.dev;
+       struct uwb_mas_bm mas;
+       struct uwb_cnflt_alien *cnflt;
+       char buf[72];
+       unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
+       
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+       bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS);
+       
+       list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
+               if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
+                       /* Existing alien BP reservation conflicting
+                        * bitmap, just reset the timer */
+                       uwb_cnflt_alien_stroke_timer(cnflt);
+                       return;
+               }
+       }
+
+       /* New alien BP reservation conflicting bitmap */
+
+       /* alloc and initialize new uwb_cnflt_alien */
+       cnflt = kzalloc(sizeof(struct uwb_cnflt_alien), GFP_KERNEL);
+       if (!cnflt)
+               dev_err(dev, "failed to alloc uwb_cnflt_alien struct\n");
+       INIT_LIST_HEAD(&cnflt->rc_node);
+       init_timer(&cnflt->timer);
+       cnflt->timer.function = uwb_cnflt_timer;
+       cnflt->timer.data     = (unsigned long)cnflt;
+
+       cnflt->rc = rc;
+       INIT_WORK(&cnflt->cnflt_update_work, uwb_cnflt_update_work);
+       
+       bitmap_copy(cnflt->mas.bm, mas.bm, UWB_NUM_MAS);
+
+       list_add_tail(&cnflt->rc_node, &rc->cnflt_alien_list);
+
+       /* update rc global conflicting alien bitmap */
+       bitmap_or(rc->cnflt_alien_bitmap.bm, rc->cnflt_alien_bitmap.bm, mas.bm, UWB_NUM_MAS);
+
+       queue_delayed_work(rc->rsv_workq, &rc->rsv_alien_bp_work, usecs_to_jiffies(delay_us));
+       
+       /* start the timer */
+       uwb_cnflt_alien_stroke_timer(cnflt);
+}
+
+static void uwb_drp_process_not_involved(struct uwb_rc *rc,
+                                        struct uwb_rc_evt_drp *drp_evt, 
+                                        struct uwb_ie_drp *drp_ie)
+{
+       struct uwb_mas_bm mas;
+       
+       uwb_drp_ie_to_bm(&mas, drp_ie);
+       uwb_drp_handle_all_conflict_rsv(rc, drp_evt, drp_ie, &mas);
+}
+
+static void 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)
 {
        struct uwb_rsv *rsv;
 
@@ -239,7 +646,7 @@ static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src,
                 */
                return;
        }
-
+       
        /*
         * Do nothing with DRP IEs for reservations that have been
         * terminated.
@@ -248,13 +655,43 @@ static void uwb_drp_process(struct uwb_rc *rc, struct uwb_dev *src,
                uwb_rsv_set_state(rsv, UWB_RSV_STATE_NONE);
                return;
        }
-
+                       
        if (uwb_ie_drp_owner(drp_ie))
-               uwb_drp_process_target(rc, rsv, drp_ie);
+               uwb_drp_process_target(rc, rsv, drp_ie, drp_evt);
+       else
+               uwb_drp_process_owner(rc, rsv, src, drp_ie, drp_evt);
+       
+}
+
+
+static bool uwb_drp_involves_us(struct uwb_rc *rc, struct uwb_ie_drp *drp_ie)
+{
+       return uwb_dev_addr_cmp(&rc->uwb_dev.dev_addr, &drp_ie->dev_addr) == 0;
+}
+
+/*
+ * Process a received DRP IE.
+ */
+static void uwb_drp_process(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
+                           struct uwb_dev *src, struct uwb_ie_drp *drp_ie)
+{
+       if (uwb_ie_drp_type(drp_ie) == UWB_DRP_TYPE_ALIEN_BP)
+               uwb_drp_handle_alien_drp(rc, drp_ie);
+       else if (uwb_drp_involves_us(rc, drp_ie))
+               uwb_drp_process_involved(rc, src, drp_evt, drp_ie);
        else
-               uwb_drp_process_owner(rc, rsv, drp_ie);
+               uwb_drp_process_not_involved(rc, drp_evt, drp_ie);
 }
 
+/*
+ * Process a received DRP Availability IE
+ */
+static void uwb_drp_availability_process(struct uwb_rc *rc, struct uwb_dev *src,
+                                        struct uwb_ie_drp_avail *drp_availability_ie)
+{
+       bitmap_copy(src->last_availability_bm,
+                   drp_availability_ie->bmp, UWB_NUM_MAS);
+}
 
 /*
  * Process all the DRP IEs (both DRP IEs and the DRP Availability IE)
@@ -276,10 +713,10 @@ void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
 
                switch (ie_hdr->element_id) {
                case UWB_IE_DRP_AVAILABILITY:
-                       /* FIXME: does something need to be done with this? */
+                       uwb_drp_availability_process(rc, src_dev, (struct uwb_ie_drp_avail *)ie_hdr);
                        break;
                case UWB_IE_DRP:
-                       uwb_drp_process(rc, src_dev, (struct uwb_ie_drp *)ie_hdr);
+                       uwb_drp_process(rc, drp_evt, src_dev, (struct uwb_ie_drp *)ie_hdr);
                        break;
                default:
                        dev_warn(dev, "unexpected IE in DRP notification\n");
@@ -292,55 +729,6 @@ void uwb_drp_process_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
                         (int)ielen);
 }
 
-
-/*
- * Go through all the DRP IEs and find the ones that conflict with our
- * reservations.
- *
- * FIXME: must resolve the conflict according the the rules in
- * [ECMA-368].
- */
-static
-void uwb_drp_process_conflict_all(struct uwb_rc *rc, struct uwb_rc_evt_drp *drp_evt,
-                                 size_t ielen, struct uwb_dev *src_dev)
-{
-       struct device *dev = &rc->uwb_dev.dev;
-       struct uwb_ie_hdr *ie_hdr;
-       struct uwb_ie_drp *drp_ie;
-       void *ptr;
-
-       ptr = drp_evt->ie_data;
-       for (;;) {
-               ie_hdr = uwb_ie_next(&ptr, &ielen);
-               if (!ie_hdr)
-                       break;
-
-               drp_ie = container_of(ie_hdr, struct uwb_ie_drp, hdr);
-
-               /* FIXME: check if this DRP IE conflicts. */
-       }
-
-       if (ielen > 0)
-               dev_warn(dev, "%d octets remaining in DRP notification\n",
-                        (int)ielen);
-}
-
-
-/*
- * Terminate all reservations owned by, or targeted at, 'uwb_dev'.
- */
-static void uwb_drp_terminate_all(struct uwb_rc *rc, struct uwb_dev *uwb_dev)
-{
-       struct uwb_rsv *rsv;
-
-       list_for_each_entry(rsv, &rc->reservations, rc_node) {
-               if (rsv->owner == uwb_dev
-                   || (rsv->target.type == UWB_RSV_TARGET_DEV && rsv->target.dev == uwb_dev))
-                       uwb_rsv_remove(rsv);
-       }
-}
-
-
 /**
  * uwbd_evt_handle_rc_drp - handle a DRP_IE event
  * @evt: the DRP_IE event from the radio controller
@@ -381,7 +769,6 @@ int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
        size_t ielength, bytes_left;
        struct uwb_dev_addr src_addr;
        struct uwb_dev *src_dev;
-       int reason;
 
        /* Is there enough data to decode the event (and any IEs in
           its payload)? */
@@ -417,22 +804,8 @@ int uwbd_evt_handle_rc_drp(struct uwb_event *evt)
 
        mutex_lock(&rc->rsvs_mutex);
 
-       reason = uwb_rc_evt_drp_reason(drp_evt);
-
-       switch (reason) {
-       case UWB_DRP_NOTIF_DRP_IE_RCVD:
-               uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
-               break;
-       case UWB_DRP_NOTIF_CONFLICT:
-               uwb_drp_process_conflict_all(rc, drp_evt, ielength, src_dev);
-               break;
-       case UWB_DRP_NOTIF_TERMINATE:
-               uwb_drp_terminate_all(rc, src_dev);
-               break;
-       default:
-               dev_warn(dev, "ignored DRP event with reason code: %d\n", reason);
-               break;
-       }
+       /* We do not distinguish from the reason */
+       uwb_drp_process_all(rc, drp_evt, ielength, src_dev);
 
        mutex_unlock(&rc->rsvs_mutex);