ra_input(void)
{
  uip_lladdr_t lladdr_aligned;

  LOG_INFO("Received RA from ");
  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
  LOG_INFO_(" to ");
  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
  LOG_INFO_("\n");
  UIP_STAT(++uip_stat.nd6.recv);

#if UIP_CONF_IPV6_CHECKS
  if((UIP_IP_BUF->ttl != UIP_ND6_HOP_LIMIT) ||
     (!uip_is_addr_linklocal(&UIP_IP_BUF->srcipaddr)) ||
     (UIP_ICMP_BUF->icode != 0)) {
    LOG_ERR("RA received is bad");
    goto discard;
  }
#endif /*UIP_CONF_IPV6_CHECKS */

  if(UIP_ND6_RA_BUF->cur_ttl != 0) {
    uip_ds6_if.cur_hop_limit = UIP_ND6_RA_BUF->cur_ttl;
    LOG_INFO("uip_ds6_if.cur_hop_limit %u\n", uip_ds6_if.cur_hop_limit);
  }

  if(UIP_ND6_RA_BUF->reachable_time != 0) {
    if(uip_ds6_if.base_reachable_time !=
       uip_ntohl(UIP_ND6_RA_BUF->reachable_time)) {
      uip_ds6_if.base_reachable_time = uip_ntohl(UIP_ND6_RA_BUF->reachable_time);
      uip_ds6_if.reachable_time = uip_ds6_compute_reachable_time();
    }
  }
  if(UIP_ND6_RA_BUF->retrans_timer != 0) {
    uip_ds6_if.retrans_timer = uip_ntohl(UIP_ND6_RA_BUF->retrans_timer);
  }

  /* Options processing */
  nd6_opt_offset = UIP_ND6_RA_LEN;
  while(uip_l3_icmp_hdr_len + nd6_opt_offset < uip_len) {
    if(ND6_OPT_HDR_BUF(nd6_opt_offset)->len == 0) {
      LOG_ERR("RA received is bad");
      goto discard;
    }
    switch (ND6_OPT_HDR_BUF(nd6_opt_offset)->type) {
    case UIP_ND6_OPT_SLLAO:
      LOG_DBG("Processing SLLAO option in RA\n");
      nd6_opt_llao = (uint8_t *) ND6_OPT_HDR_BUF(nd6_opt_offset);
      nbr = uip_ds6_nbr_lookup(&UIP_IP_BUF->srcipaddr);
      if(!extract_lladdr_from_llao_aligned(&lladdr_aligned)) {
        /* failed to extract llao - discard packet */
        goto discard;
      }
      if(nbr == NULL) {
        nbr = uip_ds6_nbr_add(&UIP_IP_BUF->srcipaddr, &lladdr_aligned,
                              1, NBR_STALE, NBR_TABLE_REASON_IPV6_ND, NULL);
      } else {
        const uip_lladdr_t *lladdr = uip_ds6_nbr_get_ll(nbr);
        if(lladdr == NULL) {
          goto discard;
        }
        if(nbr->state == NBR_INCOMPLETE) {
          nbr->state = NBR_STALE;
        }
        if(memcmp(&nd6_opt_llao[UIP_ND6_OPT_DATA_OFFSET],
                  lladdr, UIP_LLADDR_LEN) != 0) {
          /* change of link layer address */
          if(uip_ds6_nbr_update_ll(&nbr,
                                   (const uip_lladdr_t *)&lladdr_aligned) < 0) {
            /* failed to update the lladdr */
            goto discard;
          }
          nbr->state = NBR_STALE;
        }
        nbr->isrouter = 1;
      }
      break;
    case UIP_ND6_OPT_MTU:
      LOG_DBG("Processing MTU option in RA\n");
      uip_ds6_if.link_mtu =
        uip_ntohl(((uip_nd6_opt_mtu *) ND6_OPT_HDR_BUF(nd6_opt_offset))->mtu);
      break;
    case UIP_ND6_OPT_PREFIX_INFO:
      LOG_DBG("Processing PREFIX option in RA\n");
      nd6_opt_prefix_info = (uip_nd6_opt_prefix_info *) ND6_OPT_HDR_BUF(nd6_opt_offset);
      if((uip_ntohl(nd6_opt_prefix_info->validlt) >=
          uip_ntohl(nd6_opt_prefix_info->preferredlt))
         && (!uip_is_addr_linklocal(&nd6_opt_prefix_info->prefix))) {
        /* on-link flag related processing */
        if(nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_ONLINK) {
          prefix =
            uip_ds6_prefix_lookup(&nd6_opt_prefix_info->prefix,
                                  nd6_opt_prefix_info->preflen);
          if(prefix == NULL) {
            if(nd6_opt_prefix_info->validlt != 0) {
              if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) {
                prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix,
                                            nd6_opt_prefix_info->preflen,
                                            uip_ntohl(nd6_opt_prefix_info->
                                                  validlt));
              } else {
                prefix = uip_ds6_prefix_add(&nd6_opt_prefix_info->prefix,
                                            nd6_opt_prefix_info->preflen, 0);
              }
            }
          } else {
            switch (nd6_opt_prefix_info->validlt) {
            case 0:
              uip_ds6_prefix_rm(prefix);
              break;
            case UIP_ND6_INFINITE_LIFETIME:
              prefix->isinfinite = 1;
              break;
            default:
              LOG_DBG("Updating timer of prefix ");
              LOG_DBG_6ADDR(&prefix->ipaddr);
              LOG_DBG_(" new value %"PRIu32"\n", uip_ntohl(nd6_opt_prefix_info->validlt));
              stimer_set(&prefix->vlifetime,
                         uip_ntohl(nd6_opt_prefix_info->validlt));
              prefix->isinfinite = 0;
              break;
            }
          }
        }
        /* End of on-link flag related processing */
        /* autonomous flag related processing */
        if((nd6_opt_prefix_info->flagsreserved1 & UIP_ND6_RA_FLAG_AUTONOMOUS)
           && (nd6_opt_prefix_info->validlt != 0)
           && (nd6_opt_prefix_info->preflen == UIP_DEFAULT_PREFIX_LEN)) {

          uip_ipaddr_copy(&ipaddr, &nd6_opt_prefix_info->prefix);
          uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
          addr = uip_ds6_addr_lookup(&ipaddr);
          if((addr != NULL) && (addr->type == ADDR_AUTOCONF)) {
            if(nd6_opt_prefix_info->validlt != UIP_ND6_INFINITE_LIFETIME) {
              /* The processing below is defined in RFC4862 section 5.5.3 e */
              if((uip_ntohl(nd6_opt_prefix_info->validlt) > 2 * 60 * 60) ||
                 (uip_ntohl(nd6_opt_prefix_info->validlt) >
                  stimer_remaining(&addr->vlifetime))) {
                LOG_DBG("Updating timer of address ");
                LOG_DBG_6ADDR(&addr->ipaddr);
                LOG_DBG_(" new value %lu\n",
                       (unsigned long)uip_ntohl(nd6_opt_prefix_info->validlt));
                stimer_set(&addr->vlifetime,
                           uip_ntohl(nd6_opt_prefix_info->validlt));
              } else {
                stimer_set(&addr->vlifetime, 2 * 60 * 60);
                LOG_DBG("Updating timer of address ");
                LOG_DBG_6ADDR(&addr->ipaddr);
                LOG_DBG_(" new value %lu\n", (unsigned long)(2 * 60 * 60));
              }
              addr->isinfinite = 0;
            } else {
              addr->isinfinite = 1;
            }
          } else {
            if(uip_ntohl(nd6_opt_prefix_info->validlt) ==
               UIP_ND6_INFINITE_LIFETIME) {
              uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
            } else {
              uip_ds6_addr_add(&ipaddr, uip_ntohl(nd6_opt_prefix_info->validlt),
                               ADDR_AUTOCONF);
            }
          }
        }
        /* End of autonomous flag related processing */
      }
      break;
#if UIP_ND6_RA_RDNSS
    case UIP_ND6_OPT_RDNSS:
      LOG_DBG("Processing RDNSS option\n");
      uint8_t naddr = (ND6_OPT_RDNSS_BUF(nd6_opt_offset)->len - 1) / 2;
      uip_ipaddr_t *ip = (uip_ipaddr_t *)(&ND6_OPT_RDNSS_BUF(nd6_opt_offset)->ip);
      LOG_DBG("got %d nameservers\n", naddr);
      while(naddr-- > 0) {
        LOG_DBG("nameserver: ");
        LOG_DBG_6ADDR(ip);
        LOG_DBG_(" lifetime: %"PRIx32"\n", uip_ntohl(ND6_OPT_RDNSS_BUF(nd6_opt_offset)->lifetime));
        uip_nameserver_update(ip, uip_ntohl(ND6_OPT_RDNSS_BUF(nd6_opt_offset)->lifetime));
        ip++;
      }
      break;
#endif /* UIP_ND6_RA_RDNSS */
    default:
      LOG_ERR("ND option not supported in RA\n");
      break;
    }
    nd6_opt_offset += (ND6_OPT_HDR_BUF(nd6_opt_offset)->len << 3);
  }

  defrt = uip_ds6_defrt_lookup(&UIP_IP_BUF->srcipaddr);
  if(UIP_ND6_RA_BUF->router_lifetime != 0) {
    if(nbr != NULL) {
      nbr->isrouter = 1;
    }
    if(defrt == NULL) {
      uip_ds6_defrt_add(&UIP_IP_BUF->srcipaddr,
                        (unsigned
                         long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime)));
    } else {
      stimer_set(&(defrt->lifetime),
                 (unsigned long)(uip_ntohs(UIP_ND6_RA_BUF->router_lifetime)));
    }
  } else {
    if(defrt != NULL) {
      uip_ds6_defrt_rm(defrt);
    }
  }

#if UIP_CONF_IPV6_QUEUE_PKT
  /* If the nbr just became reachable (e.g. it was in NBR_INCOMPLETE state
   * and we got a SLLAO), check if we had buffered a pkt for it */
  /*  if((nbr != NULL) && (nbr->queue_buf_len != 0)) {
    uip_len = nbr->queue_buf_len;
    memcpy(UIP_IP_BUF, nbr->queue_buf, uip_len);
    nbr->queue_buf_len = 0;
    return;
    }*/
  if(nbr != NULL && uip_packetqueue_buflen(&nbr->packethandle) != 0) {
    uip_len = uip_packetqueue_buflen(&nbr->packethandle);
    memcpy(UIP_IP_BUF, uip_packetqueue_buf(&nbr->packethandle), uip_len);
    uip_packetqueue_free(&nbr->packethandle);
    return;
  }

#endif /*UIP_CONF_IPV6_QUEUE_PKT */

discard:
  uipbuf_clear();
  return;
}


uip_nd6_rs_output(void)
{
  UIP_IP_BUF->vtc = 0x60;
  UIP_IP_BUF->tcflow = 0;
  UIP_IP_BUF->flow = 0;
  UIP_IP_BUF->proto = UIP_PROTO_ICMP6;
  UIP_IP_BUF->ttl = UIP_ND6_HOP_LIMIT;
  uip_create_linklocal_allrouters_mcast(&UIP_IP_BUF->destipaddr);
  uip_ds6_select_src(&UIP_IP_BUF->srcipaddr, &UIP_IP_BUF->destipaddr);
  UIP_ICMP_BUF->type = ICMP6_RS;
  UIP_ICMP_BUF->icode = 0;

  if(uip_is_addr_unspecified(&UIP_IP_BUF->srcipaddr)) {
    UIP_IP_BUF->len[1] = UIP_ICMPH_LEN + UIP_ND6_RS_LEN;
    uip_len = uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN;
  } else {
    uip_len = uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN;
    uipbuf_set_len_field(UIP_IP_BUF, UIP_ICMPH_LEN + UIP_ND6_RS_LEN + UIP_ND6_OPT_LLAO_LEN);

    create_llao(&uip_buf[uip_l3_icmp_hdr_len + UIP_ND6_RS_LEN],
                UIP_ND6_OPT_SLLAO);
  }

  UIP_ICMP_BUF->icmpchksum = 0;
  UIP_ICMP_BUF->icmpchksum = ~uip_icmp6chksum();

  UIP_STAT(++uip_stat.nd6.sent);
  LOG_INFO("Sending RS to ");
  LOG_INFO_6ADDR(&UIP_IP_BUF->destipaddr);
  LOG_INFO_(" from ");
  LOG_INFO_6ADDR(&UIP_IP_BUF->srcipaddr);
  LOG_INFO_("\n");
  return;
}


static int handle_bb_cf_linear_sweep (RAnal *anal, RAnalState *state) {
	ut64 * paddr64;
	RAnalBlock *bb = state->current_bb;
	RAnalJavaLinearSweep *nodes = state->user_state;

	if (!nodes || !nodes->cfg_node_addrs) {
		state->done = 1;
		return R_ANAL_RET_ERROR;
	}

	ut64 addr = 0;
	int result = 0;
	if (!bb) {
		eprintf ("Error: unable to handle basic block @ 0x%08"PFMT64x"\n", addr);
		return R_ANAL_RET_ERROR;
	} else if (state->max_depth <= state->current_depth) {
		return R_ANAL_RET_ERROR;
	}

	state->current_depth++;
	addr = bb->addr;
	IFDBG eprintf ("Handling a control flow change @ 0x%04"PFMT64x".\n", addr);
	ut32 control_type = r_anal_ex_map_anal_ex_to_anal_op_type (bb->type2);

	// XXX - transition to type2 control flow condtions
	switch (control_type) {
		case R_ANAL_OP_TYPE_CALL:
			IFDBG eprintf (" - Handling a call @ 0x%04"PFMT64x"\n", addr);
			r_anal_xrefs_set (anal, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
			result = R_ANAL_RET_ERROR;
			break;
		case R_ANAL_OP_TYPE_JMP:
			paddr64 = malloc (sizeof(ut64));
			*paddr64 = bb->jump;
			IFDBG eprintf (" - Handling a jmp @ 0x%04"PFMT64x", adding for future visit\n", addr);
			r_list_append (nodes->cfg_node_addrs, paddr64);
			result = R_ANAL_RET_END;
			break;
		case R_ANAL_OP_TYPE_CJMP:
			paddr64 = malloc (sizeof(ut64));
			*paddr64 = bb->jump;
			IFDBG eprintf (" - Handling a bb->jump @ 0x%04"PFMT64x", adding 0x%04"PFMT64x" for future visit\n", addr, *paddr64);
			r_list_append (nodes->cfg_node_addrs, paddr64);
			paddr64 = malloc (sizeof(ut64));
			if (paddr64) {
				*paddr64 = bb->fail;
				IFDBG eprintf (" - Handling a bb->fail @ 0x%04"PFMT64x", adding 0x%04"PFMT64x" for future visit\n", addr, *paddr64);
				r_list_append (nodes->cfg_node_addrs, paddr64);
			}
			result = R_ANAL_RET_END;
			break;
		case R_ANAL_OP_TYPE_SWITCH:
			if (bb->switch_op) {
				RAnalCaseOp *caseop;
				RListIter *iter;
				//RList *jmp_list = NULL;
				IFDBG eprintf (" - Handling a switch_op @ 0x%04"PFMT64x":\n", addr);
				r_list_foreach (bb->switch_op->cases, iter, caseop) {
					ut64 * paddr64;
					if (caseop) {
						paddr64 = malloc (sizeof(ut64));
						*paddr64 = caseop->jump;
						IFDBG eprintf ("Adding 0x%04"PFMT64x" for future visit\n", *paddr64);
						r_list_append (nodes->cfg_node_addrs, paddr64);
					}
				}
			}
			result = R_ANAL_RET_END;
			break;
		case R_ANAL_OP_TYPE_TRAP:
		case R_ANAL_OP_TYPE_UJMP:
		case R_ANAL_OP_TYPE_RJMP:
		case R_ANAL_OP_TYPE_IJMP:
		case R_ANAL_OP_TYPE_IRJMP:
		case R_ANAL_OP_TYPE_RET:
			IFDBG eprintf (" - Handling an ret @ 0x%04"PFMT64x".\n", addr);
			state->done = 1;
			result = R_ANAL_RET_END;
			break;
		default: break;
	}

	state->current_depth--;
	return result;
}


static int check_addr_less_start (RBinJavaField *method, ut64 addr) {
	ut64 start = r_bin_java_get_method_code_offset (method);
	return (addr < start);
}


static int handle_bb_cf_recursive_descent (RAnal *anal, RAnalState *state) {

	RAnalBlock *bb = state->current_bb;

	ut64 addr = 0;
	int result = 0;
	if (!bb) {
		eprintf ("Error: unable to handle basic block @ 0x%08"PFMT64x"\n", addr);
		return R_ANAL_RET_ERROR;
	} else if (state->max_depth <= state->current_depth) {
		return R_ANAL_RET_ERROR;
	}

	state->current_depth++;
	addr = bb->addr;
	IFDBG eprintf ("Handling a control flow change @ 0x%04"PFMT64x".\n", addr);
	ut64 control_type = r_anal_ex_map_anal_ex_to_anal_op_type (bb->type2);

	// XXX - transition to type2 control flow condtions
	switch (control_type) {
		case R_ANAL_OP_TYPE_CALL:
			IFDBG eprintf (" - Handling a call @ 0x%04"PFMT64x".\n", addr);
			r_anal_xrefs_set (anal, bb->addr, bb->jump, R_ANAL_REF_TYPE_CALL);
			result = R_ANAL_RET_ERROR;
			break;
		case R_ANAL_OP_TYPE_JMP:
			{
				RList * jmp_list;
				IFDBG eprintf (" - Handling a jmp @ 0x%04"PFMT64x" to 0x%04"PFMT64x".\n", addr, bb->jump);

				// visited some other time
				if (!r_anal_state_search_bb (state, bb->jump)) {
					jmp_list = r_anal_ex_perform_analysis ( anal, state, bb->jump );
					if (jmp_list)
						bb->jumpbb = (RAnalBlock *) r_list_get_n (jmp_list, 0);
					if (bb->jumpbb)
						bb->jump = bb->jumpbb->addr;
				} else {
					bb->jumpbb = r_anal_state_search_bb (state, bb->jump);
					if (bb->jumpbb)
						bb->jump = bb->jumpbb->addr;
				}

				if (state->done == 1) {
					IFDBG eprintf (" Looks like this jmp (bb @ 0x%04"PFMT64x") found a return.\n", addr);
				}
				result = R_ANAL_RET_END;
			}
			break;
		case R_ANAL_OP_TYPE_CJMP:
			{
				RList *jmp_list;
				ut8 encountered_stop = 0;
				IFDBG eprintf (" - Handling a cjmp @ 0x%04"PFMT64x" jmp to 0x%04"PFMT64x" and fail to 0x%04"PFMT64x".\n", addr, bb->jump, bb->fail);
				IFDBG eprintf (" - Handling jmp to 0x%04"PFMT64x".\n", bb->jump);
				// visited some other time
				if (!r_anal_state_search_bb (state, bb->jump)) {
					jmp_list = r_anal_ex_perform_analysis ( anal, state, bb->jump );
					if (jmp_list)
						bb->jumpbb = (RAnalBlock *) r_list_get_n (jmp_list, 0);
					if (bb->jumpbb) {
						bb->jump = bb->jumpbb->addr;
					}
				} else {
					bb->jumpbb = r_anal_state_search_bb (state, bb->jump);
					bb->jump = bb->jumpbb->addr;
				}

				if (state->done == 1) {
					IFDBG eprintf (" Looks like this jmp (bb @ 0x%04"PFMT64x") found a return.\n", addr);
					state->done = 0;
					encountered_stop = 1;
				}

				if (!r_anal_state_search_bb (state, bb->fail)) {
					jmp_list = r_anal_ex_perform_analysis ( anal, state, bb->fail );
					if (jmp_list)
						bb->failbb = (RAnalBlock *) r_list_get_n (jmp_list, 0);
					if (bb->failbb) {
						bb->fail = bb->failbb->addr;
					}
				} else {
					bb->failbb = r_anal_state_search_bb (state, bb->fail);
					if (bb->failbb) {
						bb->fail = bb->failbb->addr;
					}
				}

				IFDBG eprintf (" - Handling an cjmp @ 0x%04"PFMT64x" jmp to 0x%04"PFMT64x" and fail to 0x%04"PFMT64x".\n", addr, bb->jump, bb->fail);
				IFDBG eprintf (" - Handling fail to 0x%04"PFMT64x".\n", bb->fail);
				// r_anal_state_merge_bb_list (state, fail_list);
				if (state->done == 1) {
					IFDBG eprintf (" Looks like this fail (bb @ 0x%04"PFMT64x") found a return.\n", addr);
				}

				result = R_ANAL_RET_END;
				if (encountered_stop) state->done = 1;
			}
			break;

		case R_ANAL_OP_TYPE_SWITCH:
		{
			IFDBG eprintf (" - Handling an switch @ 0x%04"PFMT64x".\n", addr);
			if (bb->switch_op) {
				RAnalCaseOp *caseop;
				RListIter *iter;
				RList *jmp_list = NULL;
				ut8 encountered_stop = 0;
				r_list_foreach (bb->switch_op->cases, iter, caseop) {
					if (caseop) {
						if (r_anal_state_addr_is_valid (state, caseop->jump) ) {
							jmp_list = r_anal_ex_perform_analysis ( anal, state, caseop->jump );
							if (jmp_list)
								caseop->jumpbb = (RAnalBlock *) r_list_get_n (jmp_list, 0);
							if (state->done == 1) {
								IFDBG eprintf (" Looks like this jmp (bb @ 0x%04"PFMT64x") found a return.\n", addr);
								state->done = 0;
								encountered_stop = 1;
							}
						}
					}
				}
				r_list_free (jmp_list);
				if (encountered_stop) state->done = 1;
			}

			result = R_ANAL_RET_END;
		}
			break;
		case R_ANAL_OP_TYPE_TRAP:
		case R_ANAL_OP_TYPE_UJMP:
		case R_ANAL_OP_TYPE_IJMP:
		case R_ANAL_OP_TYPE_RJMP:
		case R_ANAL_OP_TYPE_IRJMP:
		case R_ANAL_OP_TYPE_RET:
		case R_ANAL_OP_TYPE_ILL:
			IFDBG eprintf (" - Handling an ret @ 0x%04"PFMT64x".\n", addr);
			state->done = 1;
			result = R_ANAL_RET_END;
			break;
		default: break;
	}

	state->current_depth--;
	return result;
}


coolkey_make_new_id(unsigned long object_id, unsigned long id_type)
{ return ((object_id  & 0x00ffffffUL)|(id_type << 24)); }


coolkey_set_bool_flags(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, unsigned int *flags_ptr, struct coolkey_attr_flags *table, int table_size)
{
	unsigned int flags = 0;
	int i;

	for (i=0; i< table_size; i++) {
		if (coolkey_get_attribute_boolean(card, obj, table[i].attribute_type)) {
			flags |= table[i].pkcs15_flags;
		}
	}
	*flags_ptr = flags;
	return SC_SUCCESS;
}


coolkey_get_public_key(sc_pkcs15_card_t *p15card, sc_cardctl_coolkey_object_t *obj, CK_KEY_TYPE key_type)
{
	sc_pkcs15_pubkey_t *key;

	key = coolkey_make_public_key(p15card->card, obj, key_type);
	if (key) {
		return key;
	}
	return coolkey_get_public_key_from_certificate(p15card, obj);
}


coolkey_get_attribute_bytes(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, u8 *data, size_t *data_len, size_t max_data_len)
{
	const u8 *val;
	size_t val_len;
	int r;

	r = coolkey_get_attribute(card, obj, type, &val, &val_len, NULL);
	if (r < 0) {
		return r;
	}
	if (val_len > max_data_len) {
		val_len = max_data_len;
	}
	memcpy(data, val, val_len);
	*data_len = val_len;
	return SC_SUCCESS;
}


coolkey_get_attribute(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, const u8 **val, size_t *val_len, u8 *data_type) {
	sc_cardctl_coolkey_attribute_t attribute;
	int r;

	attribute.object = obj;
	attribute.attribute_type = type;

	r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_GET_ATTRIBUTE, &attribute);
	if (r < 0) {
		return r;
	}
	*val = attribute.attribute_value;
	*val_len = attribute.attribute_length;
	if (data_type) {
		*data_type = attribute.attribute_data_type;
	}
	return SC_SUCCESS;
}


coolkey_get_id(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, struct sc_pkcs15_id *id)
{
	return coolkey_get_attribute_bytes(card, obj, CKA_ID, id->value , &id->len, sizeof(id->value));
}


static int insert_pin(
	sc_pkcs15_card_t *p15card,
	const char       *path,
	unsigned char     id,
	unsigned char     auth_id,
	unsigned char     pin_reference,
	int               min_length,
	const char       *label,
	int               pin_flags
){
	sc_card_t *card=p15card->card;
	sc_context_t *ctx=p15card->card->ctx;
	sc_file_t *f = NULL;
	struct sc_pkcs15_auth_info pin_info;
	struct sc_pkcs15_object pin_obj;
	int r;

	memset(&pin_info, 0, sizeof(pin_info));
	pin_info.auth_id.len      = 1;
	pin_info.auth_id.value[0] = id;
	pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
	pin_info.attrs.pin.reference        = pin_reference;
	pin_info.attrs.pin.flags            = pin_flags;
	pin_info.attrs.pin.type             = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
	pin_info.attrs.pin.min_length       = min_length;
	pin_info.attrs.pin.stored_length    = 16;
	pin_info.attrs.pin.max_length       = 16;
	pin_info.attrs.pin.pad_char         = '\0';
	pin_info.logged_in = SC_PIN_STATE_UNKNOWN;
	sc_format_path(path, &pin_info.path);

	memset(&pin_obj, 0, sizeof(pin_obj));
	strlcpy(pin_obj.label, label, sizeof(pin_obj.label));
	pin_obj.flags            = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
	pin_obj.auth_id.len      = auth_id ? 0 : 1;
	pin_obj.auth_id.value[0] = auth_id;

	if(card->type == SC_CARD_TYPE_TCOS_V3) {
		unsigned char buf[256];
		int i, rec_no=0;
		if (pin_info.path.len >= 2) {
			pin_info.path.len -= 2;
		}
		sc_append_file_id(&pin_info.path, 0x5049);
		if (sc_select_file(card, &pin_info.path, NULL) != SC_SUCCESS) {
			sc_log(ctx,
				"Select(%s) failed\n",
				sc_print_path(&pin_info.path));
			return 1;
		}
		sc_log(ctx,
			"Searching for PIN-Ref %02X\n", pin_reference);
		while ((r = sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR)) > 0) {
			int found = 0, fbz = -1;
			if (r < 2 || buf[0] != 0xA0)
				continue;
			for (i = 2; i < buf[1] + 2 && (i + 2) < r; i += 2 + buf[i + 1]) {
				if (buf[i] == 0x83 && buf[i + 1] == 1 && buf[i + 2] == pin_reference) {
					++found;
				}
				if (buf[i] == 0x90 && (i + 1 + buf[i + 1]) < r) {
					fbz = buf[i + 1 + buf[i + 1]];
				}
			}
			if (found) {
				pin_info.tries_left = fbz;
				break;
			}
		}
		if (r <= 0) {
			sc_log(ctx, "No EF_PWDD-Record found\n");
			return 1;
		}
	} else {
		if (sc_select_file(card, &pin_info.path, &f) != SC_SUCCESS
			   	|| !f->prop_attr || f->prop_attr_len < 4){
			sc_log(ctx, "Select(%s) failed\n", path);
			sc_file_free(f);
			return 1;
		}
		pin_info.tries_left = f->prop_attr[3];
		sc_file_free(f);
	}

	r=sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
	if(r!=SC_SUCCESS){
		sc_log(ctx,  "sc_pkcs15emu_add_pin_obj(%s) failed\n", path);
		return 4;
	}
	sc_log(ctx,  "%s: OK, FBZ=%d\n", path, pin_info.tries_left);
	return 0;
}


static void decode_bitmap_rgb24(deark *c, lctx *d, struct fmtutil_macbitmap_info *bi,
	dbuf *unc_pixels, de_bitmap *img, i64 pos)
{
	i64 i, j;
	u8 cr, cg, cb;

	for(j=0; j<bi->height; j++) {
		for(i=0; i<bi->pdwidth; i++) {
			cr = dbuf_getbyte(unc_pixels, j*bi->rowspan + (bi->cmpcount-3+0)*bi->pdwidth + i);
			cg = dbuf_getbyte(unc_pixels, j*bi->rowspan + (bi->cmpcount-3+1)*bi->pdwidth + i);
			cb = dbuf_getbyte(unc_pixels, j*bi->rowspan + (bi->cmpcount-3+2)*bi->pdwidth + i);
			de_bitmap_setpixel_rgb(img, i, j, DE_MAKE_RGB(cr,cg,cb));
		}
	}
}


static int get_ngot_entries(struct r_bin_bflt_obj *obj) {
	ut32 data_size = obj->hdr->data_end - obj->hdr->data_start;
	int i = 0, n_got = 0;
	if (data_size > obj->size) {
		return 0;
	}
	for (i = 0, n_got = 0; i < data_size ; i+= 4, n_got++) {
		ut32 entry, offset = obj->hdr->data_start;
		if (offset + i + sizeof (ut32) > obj->size ||
		    offset + i + sizeof (ut32) < offset) {
			return 0;
		}
		int len = r_buf_read_at (obj->b, offset + i, (ut8 *)&entry,
					 sizeof (ut32));
		if (len != sizeof (ut32)) {
			return 0;
		}
		if (!VALID_GOT_ENTRY (entry)) {
			break;
		}
	}
	return n_got;
}


void AcceptRoutingHandler<Pipeline, R>::onRoutingData(
    uint64_t connId,
    typename RoutingDataHandler<R>::RoutingData& routingData) {
  // Get the routing pipeline corresponding to this connection
  auto routingPipelineIter = routingPipelines_.find(connId);
  if (routingPipelineIter == routingPipelines_.end()) {
    VLOG(2) << "Connection has already been closed, "
               "or routed to a worker thread.";
    return;
  }
  auto routingPipeline = std::move(routingPipelineIter->second);
  routingPipelines_.erase(routingPipelineIter);

  // Fetch the socket from the pipeline and pause reading from the
  // socket
  auto socket = std::dynamic_pointer_cast<folly::AsyncTransportWrapper>(
      routingPipeline->getTransport());
  CHECK(socket);
  routingPipeline->transportInactive();
  socket->detachEventBase();

  // Hash based on routing data to pick a new acceptor
  uint64_t hash = std::hash<R>()(routingData.routingData);
  auto acceptor = acceptors_[hash % acceptors_.size()];

  // Switch to the new acceptor's thread
  acceptor->getEventBase()->runInEventBaseThread(
      [ =, routingData = std::move(routingData) ]() mutable {
        socket->attachEventBase(acceptor->getEventBase());

        auto routingHandler =
            routingPipeline->template getHandler<RoutingDataHandler<R>>();
        DCHECK(routingHandler);
        auto transportInfo = routingPipeline->getTransportInfo();
        auto pipeline = childPipelineFactory_->newPipeline(
            socket, routingData.routingData, routingHandler, transportInfo);

        auto connection =
            new typename ServerAcceptor<Pipeline>::ServerConnection(pipeline);
        acceptor->addConnection(connection);

        pipeline->transportActive();

        // Pass in the buffered bytes to the pipeline
        pipeline->read(routingData.bufQueue);
      });
}


void AcceptRoutingHandler<Pipeline, R>::readException(
    Context*,
    folly::exception_wrapper) {
  // Null implementation to terminate the call in this handler
}


static av_always_inline void paint_raw(uint8_t *dst, int w, int h,
                                       GetByteContext *gb, int bpp,
                                       int be, int stride)
{
    int i, j, p;
    for (j = 0; j < h; j++) {
        for (i = 0; i < w; i++) {
            p = vmnc_get_pixel(gb, bpp, be);
            switch (bpp) {
            case 1:
                dst[i] = p;
                break;
            case 2:
                ((uint16_t*)dst)[i] = p;
                break;
            case 4:
                ((uint32_t*)dst)[i] = p;
                break;
            }
        }
        dst += stride;
    }
}


static av_always_inline void paint_rect(uint8_t *dst, int dx, int dy,
                                        int w, int h, int color,
                                        int bpp, int stride)
{
    int i, j;
    dst += dx * bpp + dy * stride;
    if (bpp == 1) {
        for (j = 0; j < h; j++) {
            memset(dst, color, w);
            dst += stride;
        }
    } else if (bpp == 2) {
        uint16_t *dst2;
        for (j = 0; j < h; j++) {
            dst2 = (uint16_t*)dst;
            for (i = 0; i < w; i++)
                *dst2++ = color;
            dst += stride;
        }
    } else if (bpp == 4) {
        uint32_t *dst2;
        for (j = 0; j < h; j++) {
            dst2 = (uint32_t*)dst;
            for (i = 0; i < w; i++)
                dst2[i] = color;
            dst += stride;
        }
    }
}


  static inline int GetSliceShape(const int slice_index, const int split_size,
                                  const int residual) {
    DCHECK_GT(split_size, 0);
    DCHECK_GE(slice_index, 0);
    if (residual == 0) return split_size;
    if (slice_index < residual) {
      return split_size + 1;
    } else {
      return split_size;
    }
  }


  static inline ShapeArray UndefinedOrder(const VarDimArray shape) {
    return ShapeArray(shape.size(), -1);
  }


future<std::unique_ptr<cql_server::response>> cql_server::connection::process_options(uint16_t stream, request_reader in, service::client_state& client_state,
        tracing::trace_state_ptr trace_state) {
    ++_server._stats.options_requests;
    return make_ready_future<std::unique_ptr<cql_server::response>>(make_supported(stream, std::move(trace_state)));
}


    virtual void visit(const messages::result_message::void_message&) override {
        _response.write_int(0x0001);
    }


static inline cql_server::result_with_foreign_response_ptr convert_error_message_to_coordinator_result(messages::result_message* msg) {
    return std::move(*dynamic_cast<messages::result_message::exception*>(msg)).get_exception();
}


void cql_server::response::write_value(bytes_opt value)
{
    if (!value) {
        write_int(-1);
        return;
    }

    write_int(value->size());
    _body.write(*value);
}


cql_server::connection::connection(cql_server& server, socket_address server_addr, connected_socket&& fd, socket_address addr)
    : generic_server::connection{server, std::move(fd)}
    , _server(server)
    , _server_addr(server_addr)
    , _client_state(service::client_state::external_tag{}, server._auth_service, &server._sl_controller, server.timeout_config(), addr)
{
    _shedding_timer.set_callback([this] {
        clogger.debug("Shedding all incoming requests due to overload");
        _shed_incoming_requests = true;
    });
}


process_execute_internal(service::client_state& client_state, distributed<cql3::query_processor>& qp, request_reader in,
        uint16_t stream, cql_protocol_version_type version, cql_serialization_format serialization_format,
        service_permit permit, tracing::trace_state_ptr trace_state, bool init_trace, cql3::computed_function_values cached_pk_fn_calls) {
    cql3::prepared_cache_key_type cache_key(in.read_short_bytes());
    auto& id = cql3::prepared_cache_key_type::cql_id(cache_key);
    bool needs_authorization = false;

    // First, try to lookup in the cache of already authorized statements. If the corresponding entry is not found there
    // look for the prepared statement and then authorize it.
    auto prepared = qp.local().get_prepared(client_state.user(), cache_key);
    if (!prepared) {
        needs_authorization = true;
        prepared = qp.local().get_prepared(cache_key);
    }

    if (!prepared) {
        throw exceptions::prepared_query_not_found_exception(id);
    }

    auto q_state = std::make_unique<cql_query_state>(client_state, trace_state, std::move(permit));
    auto& query_state = q_state->query_state;
    if (version == 1) {
        std::vector<cql3::raw_value_view> values;
        in.read_value_view_list(version, values);
        auto consistency = in.read_consistency();
        q_state->options = std::make_unique<cql3::query_options>(qp.local().get_cql_config(), consistency, std::nullopt, values, false,
                                                                 cql3::query_options::specific_options::DEFAULT, serialization_format);
    } else {
        q_state->options = in.read_options(version, serialization_format, qp.local().get_cql_config());
    }
    auto& options = *q_state->options;
    if (!cached_pk_fn_calls.empty()) {
        options.set_cached_pk_function_calls(std::move(cached_pk_fn_calls));
    }
    auto skip_metadata = options.skip_metadata();

    if (init_trace) {
        tracing::set_page_size(trace_state, options.get_page_size());
        tracing::set_consistency_level(trace_state, options.get_consistency());
        tracing::set_optional_serial_consistency_level(trace_state, options.get_serial_consistency());
        tracing::add_query(trace_state, prepared->statement->raw_cql_statement);
        tracing::add_prepared_statement(trace_state, prepared);

        tracing::begin(trace_state, seastar::value_of([&id] { return seastar::format("Execute CQL3 prepared query [{}]", id); }),
                client_state.get_client_address());
    }

    auto stmt = prepared->statement;
    tracing::trace(query_state.get_trace_state(), "Checking bounds");
    if (stmt->get_bound_terms() != options.get_values_count()) {
        const auto msg = format("Invalid amount of bind variables: expected {:d} received {:d}",
                stmt->get_bound_terms(),
                options.get_values_count());
        tracing::trace(query_state.get_trace_state(), msg);
        throw exceptions::invalid_request_exception(msg);
    }

    options.prepare(prepared->bound_names);

    if (init_trace) {
        tracing::add_prepared_query_options(trace_state, options);
    }

    tracing::trace(trace_state, "Processing a statement");
    return qp.local().execute_prepared_without_checking_exception_message(std::move(prepared), std::move(cache_key), query_state, options, needs_authorization)
            .then([trace_state = query_state.get_trace_state(), skip_metadata, q_state = std::move(q_state), stream, version] (auto msg) {
        if (msg->move_to_shard()) {
            return process_fn_return_type(dynamic_pointer_cast<messages::result_message::bounce_to_shard>(msg));
        } else if (msg->is_exception()) {
            return process_fn_return_type(convert_error_message_to_coordinator_result(msg.get()));
        } else {
            tracing::trace(q_state->query_state.get_trace_state(), "Done processing - preparing a result");
            return process_fn_return_type(make_foreign(make_result(stream, *msg, q_state->query_state.get_trace_state(), version, skip_metadata)));
        }
    });
}


cql_server::connection::make_schema_change_event(const event::schema_change& event) const
{
    auto response = std::make_unique<cql_server::response>(-1, cql_binary_opcode::EVENT, tracing::trace_state_ptr());
    response->write_string("SCHEMA_CHANGE");
    response->serialize(event, _version);
    return response;
}


std::unique_ptr<cql_server::response> cql_server::connection::make_supported(int16_t stream, const tracing::trace_state_ptr& tr_state) const
{
    std::multimap<sstring, sstring> opts;
    opts.insert({"CQL_VERSION", cql3::query_processor::CQL_VERSION});
    opts.insert({"COMPRESSION", "lz4"});
    opts.insert({"COMPRESSION", "snappy"});
    if (_server._config.allow_shard_aware_drivers) {
        opts.insert({"SCYLLA_SHARD", format("{:d}", this_shard_id())});
        opts.insert({"SCYLLA_NR_SHARDS", format("{:d}", smp::count)});
        opts.insert({"SCYLLA_SHARDING_ALGORITHM", dht::cpu_sharding_algorithm_name()});
        if (_server._config.shard_aware_transport_port) {
            opts.insert({"SCYLLA_SHARD_AWARE_PORT", format("{:d}", *_server._config.shard_aware_transport_port)});
        }
        if (_server._config.shard_aware_transport_port_ssl) {
            opts.insert({"SCYLLA_SHARD_AWARE_PORT_SSL", format("{:d}", *_server._config.shard_aware_transport_port_ssl)});
        }
        opts.insert({"SCYLLA_SHARDING_IGNORE_MSB", format("{:d}", _server._config.sharding_ignore_msb)});
        opts.insert({"SCYLLA_PARTITIONER", _server._config.partitioner_name});
    }
    for (cql_protocol_extension ext : supported_cql_protocol_extensions()) {
        const sstring ext_key_name = protocol_extension_name(ext);
        std::vector<sstring> params = additional_options_for_proto_ext(ext);
        if (params.empty()) {
            opts.emplace(ext_key_name, "");
        } else {
            for (sstring val : params) {
                opts.emplace(ext_key_name, std::move(val));
            }
        }
    }
    auto response = std::make_unique<cql_server::response>(stream, cql_binary_opcode::SUPPORTED, tr_state);
    response->write_string_multimap(std::move(opts));
    return response;
}


void cql_server::response::compress(cql_compression compression)
{
    switch (compression) {
    case cql_compression::lz4:
        compress_lz4();
        break;
    case cql_compression::snappy:
        compress_snappy();
        break;
    default:
        throw std::invalid_argument("Invalid CQL compression algorithm");
    }
    set_frame_flag(cql_frame_flags::compression);
}


sstring to_string(const event::status_change::status_type t) {
    using type = event::status_change::status_type;
    switch (t) {
    case type::UP:   return "UP";
    case type::DOWN: return "DOWN";
    }
    throw std::invalid_argument("unknown change type");
}


cql_server::response::placeholder<int32_t> cql_server::response::write_int_placeholder() {
    return placeholder<int32_t>(_body.write_place_holder(sizeof(int32_t)));
}


static void seq_drain_midi_queues(void)
{
	int i, n;

	/*
	 * Give the Midi drivers time to drain their output queues
	 */

	n = 1;

	while (!signal_pending(current) && n)
	{
		n = 0;

		for (i = 0; i < max_mididev; i++)
			if (midi_opened[i] && midi_written[i])
				if (midi_devs[i]->buffer_status != NULL)
					if (midi_devs[i]->buffer_status(i))
						n++;

		/*
		 * Let's have a delay
		 */

 		if (n)
 			interruptible_sleep_on_timeout(&seq_sleeper,
						       HZ/10);
	}
}


void seq_copy_to_input(unsigned char *event_rec, int len)
{
	unsigned long flags;

	/*
	 * Verify that the len is valid for the current mode.
	 */

	if (len != 4 && len != 8)
		return;
	if ((seq_mode == SEQ_1) != (len == 4))
		return;

	if (iqlen >= (SEQ_MAX_QUEUE - 1))
		return;		/* Overflow */

	spin_lock_irqsave(&lock,flags);
	memcpy(&iqueue[iqtail * IEV_SZ], event_rec, len);
	iqlen++;
	iqtail = (iqtail + 1) % SEQ_MAX_QUEUE;
	wake_up(&midi_sleeper);
	spin_unlock_irqrestore(&lock,flags);
}


void sequencer_release(int dev, struct file *file)
{
	int i;
	int mode = translate_mode(file);

	dev = dev >> 4;

	DEB(printk("sequencer_release(dev=%d)\n", dev));

	/*
	 * Wait until the queue is empty (if we don't have nonblock)
	 */

	if (mode != OPEN_READ && !(file->f_flags & O_NONBLOCK))
	{
		while (!signal_pending(current) && qlen > 0)
		{
  			seq_sync();
 			interruptible_sleep_on_timeout(&seq_sleeper,
						       3*HZ);
 			/* Extra delay */
		}
	}

	if (mode != OPEN_READ)
		seq_drain_midi_queues();	/*
						 * Ensure the output queues are empty
						 */
	seq_reset();
	if (mode != OPEN_READ)
		seq_drain_midi_queues();	/*
						 * Flush the all notes off messages
						 */

	for (i = 0; i < max_synthdev; i++)
	{
		if (synth_open_mask & (1 << i))	/*
						 * Actually opened
						 */
			if (synth_devs[i])
			{
				synth_devs[i]->close(i);

				module_put(synth_devs[i]->owner);

				if (synth_devs[i]->midi_dev)
					midi_opened[synth_devs[i]->midi_dev] = 0;
			}
	}

	for (i = 0; i < max_mididev; i++)
	{
		if (midi_opened[i]) {
			midi_devs[i]->close(i);
			module_put(midi_devs[i]->owner);
		}
	}

	if (seq_mode == SEQ_2) {
		tmr->close(tmr_no);
		module_put(tmr->owner);
	}

	if (obsolete_api_used)
		printk(KERN_WARNING "/dev/music: Obsolete (4 byte) API was used by %s\n", current->comm);
	sequencer_busy = 0;
}


midi_synth_start_note(int dev, int channel, int note, int velocity)
{
	int             orig_dev = synth_devs[dev]->midi_dev;
	int             msg, chn;

	if (note < 0 || note > 127)
		return 0;
	if (channel < 0 || channel > 15)
		return 0;
	if (velocity < 0)
		velocity = 0;
	if (velocity > 127)
		velocity = 127;

	leave_sysex(dev);

	msg = prev_out_status[orig_dev] & 0xf0;
	chn = prev_out_status[orig_dev] & 0x0f;

	if (chn == channel && msg == 0x90)
	  {			/*
				 * Use running status
				 */
		  if (!prefix_cmd(orig_dev, note))
			  return 0;
		  midi_outc(orig_dev, note);
		  midi_outc(orig_dev, velocity);
	} else
	  {
		  if (!prefix_cmd(orig_dev, 0x90 | (channel & 0x0f)))
			  return 0;
		  midi_outc(orig_dev, 0x90 | (channel & 0x0f));		/*
									 * Note on
									 */
		  midi_outc(orig_dev, note);
		  midi_outc(orig_dev, velocity);
	  }
	return 0;
}


void sequencer_timer(unsigned long dummy)
{
	seq_startplay();
}


midi_synth_send_sysex(int dev, unsigned char *bytes, int len)
{
	int             orig_dev = synth_devs[dev]->midi_dev;
	int             i;

	for (i = 0; i < len; i++)
	  {
		  switch (bytes[i])
		    {
		    case 0xf0:	/* Start sysex */
			    if (!prefix_cmd(orig_dev, 0xf0))
				    return 0;
			    sysex_state[dev] = 1;
			    break;

		    case 0xf7:	/* End sysex */
			    if (!sysex_state[dev])	/* Orphan sysex end */
				    return 0;
			    sysex_state[dev] = 0;
			    break;

		    default:
			    if (!sysex_state[dev])
				    return 0;

			    if (bytes[i] & 0x80)	/* Error. Another message before sysex end */
			      {
				      bytes[i] = 0xf7;	/* Sysex end */
				      sysex_state[dev] = 0;
			      }
		    }

		  if (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]))
		    {
/*
 * Hardware level buffer is full. Abort the sysex message.
 */

			    int             timeout = 0;

			    bytes[i] = 0xf7;
			    sysex_state[dev] = 0;

			    while (!midi_devs[orig_dev]->outputc(orig_dev, bytes[i]) &&
				   timeout < 1000)
				    timeout++;
		    }
		  if (!sysex_state[dev])
			  return 0;
	  }

	return 0;
}


void sequencer_init(void)
{
	if (sequencer_ok)
		return;
	queue = vmalloc(SEQ_MAX_QUEUE * EV_SZ);
	if (queue == NULL)
	{
		printk(KERN_ERR "sequencer: Can't allocate memory for sequencer output queue\n");
		return;
	}
	iqueue = vmalloc(SEQ_MAX_QUEUE * IEV_SZ);
	if (iqueue == NULL)
	{
		printk(KERN_ERR "sequencer: Can't allocate memory for sequencer input queue\n");
		vfree(queue);
		return;
	}
	sequencer_ok = 1;
}


static void sequencer_midi_input(int dev, unsigned char data)
{
	unsigned int tstamp;
	unsigned char event_rec[4];

	if (data == 0xfe)	/* Ignore active sensing */
		return;

	tstamp = jiffies - seq_time;

	if (tstamp != prev_input_time)
	{
		tstamp = (tstamp << 8) | SEQ_WAIT;
		seq_copy_to_input((unsigned char *) &tstamp, 4);
		prev_input_time = tstamp;
	}
	event_rec[0] = SEQ_MIDIPUTC;
	event_rec[1] = data;
	event_rec[2] = dev;
	event_rec[3] = 0;

	seq_copy_to_input(event_rec, 4);
}


static void sequencer_midi_output(int dev)
{
	/*
	 * Currently NOP
	 */
}


int DocumentSourceGroup::freeMemory() {
    invariant(_groups);
    int totalMemorySaved = 0;
    for (auto&& group : *_groups) {
        for (auto&& groupObj : group.second) {
            auto prevMemUsage = groupObj->memUsageForSorter();
            groupObj->reduceMemoryConsumptionIfAble();

            // Update the memory usage for this group.
            totalMemorySaved += (prevMemUsage - groupObj->memUsageForSorter());
        }
    }
    return totalMemorySaved;
}


boost::optional<DocumentSource::DistributedPlanLogic> DocumentSourceGroup::distributedPlanLogic() {
    intrusive_ptr<DocumentSourceGroup> mergingGroup(new DocumentSourceGroup(pExpCtx));
    mergingGroup->setDoingMerge(true);

    VariablesParseState vps = pExpCtx->variablesParseState;
    /* the merger will use the same grouping key */
    mergingGroup->setIdExpression(ExpressionFieldPath::parse(pExpCtx, "$$ROOT._id", vps));

    for (auto&& accumulatedField : _accumulatedFields) {
        // The merger's output field names will be the same, as will the accumulator factories.
        // However, for some accumulators, the expression to be accumulated will be different. The
        // original accumulator may be collecting an expression based on a field expression or
        // constant.  Here, we accumulate the output of the same name from the prior group.
        auto copiedAccumulatedField = accumulatedField;
        copiedAccumulatedField.expr.argument =
            ExpressionFieldPath::parse(pExpCtx, "$$ROOT." + copiedAccumulatedField.fieldName, vps);
        mergingGroup->addAccumulator(copiedAccumulatedField);
    }

    // {shardsStage, mergingStage, sortPattern}
    return DistributedPlanLogic{this, mergingGroup, boost::none};
}


bool DocumentSourceGroup::usedDisk() {
    return _usedDisk;
}


static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
	const struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
	__be32 x_recv, pinv;

	if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
		return 0;

	if (dccp_packet_without_ack(skb))
		return 0;

	x_recv = htonl(hc->rx_x_recv);
	pinv   = htonl(hc->rx_pinv);

	if (dccp_insert_option(skb, TFRC_OPT_LOSS_EVENT_RATE,
			       &pinv, sizeof(pinv)) ||
	    dccp_insert_option(skb, TFRC_OPT_RECEIVE_RATE,
			       &x_recv, sizeof(x_recv)))
		return -1;

	return 0;
}


static void ccid3_hc_tx_no_feedback_timer(unsigned long data)
{
	struct sock *sk = (struct sock *)data;
	struct ccid3_hc_tx_sock *hc = ccid3_hc_tx_sk(sk);
	unsigned long t_nfb = USEC_PER_SEC / 5;

	bh_lock_sock(sk);
	if (sock_owned_by_user(sk)) {
		/* Try again later. */
		/* XXX: set some sensible MIB */
		goto restart_timer;
	}

	ccid3_pr_debug("%s(%p, state=%s) - entry\n", dccp_role(sk), sk,
		       ccid3_tx_state_name(hc->tx_state));

	/* Ignore and do not restart after leaving the established state */
	if ((1 << sk->sk_state) & ~(DCCPF_OPEN | DCCPF_PARTOPEN))
		goto out;

	/* Reset feedback state to "no feedback received" */
	if (hc->tx_state == TFRC_SSTATE_FBACK)
		ccid3_hc_tx_set_state(sk, TFRC_SSTATE_NO_FBACK);

	/*
	 * Determine new allowed sending rate X as per draft rfc3448bis-00, 4.4
	 * RTO is 0 if and only if no feedback has been received yet.
	 */
	if (hc->tx_t_rto == 0 || hc->tx_p == 0) {

		/* halve send rate directly */
		hc->tx_x = max(hc->tx_x / 2,
			       (((__u64)hc->tx_s) << 6) / TFRC_T_MBI);
		ccid3_update_send_interval(hc);
	} else {
		/*
		 *  Modify the cached value of X_recv
		 *
		 *  If (X_calc > 2 * X_recv)
		 *    X_recv = max(X_recv / 2, s / (2 * t_mbi));
		 *  Else
		 *    X_recv = X_calc / 4;
		 *
		 *  Note that X_recv is scaled by 2^6 while X_calc is not
		 */
		if (hc->tx_x_calc > (hc->tx_x_recv >> 5))
			hc->tx_x_recv =
				max(hc->tx_x_recv / 2,
				    (((__u64)hc->tx_s) << 6) / (2*TFRC_T_MBI));
		else {
			hc->tx_x_recv = hc->tx_x_calc;
			hc->tx_x_recv <<= 4;
		}
		ccid3_hc_tx_update_x(sk, NULL);
	}
	ccid3_pr_debug("Reduced X to %llu/64 bytes/sec\n",
			(unsigned long long)hc->tx_x);

	/*
	 * Set new timeout for the nofeedback timer.
	 * See comments in packet_recv() regarding the value of t_RTO.
	 */
	if (unlikely(hc->tx_t_rto == 0))	/* no feedback received yet */
		t_nfb = TFRC_INITIAL_TIMEOUT;
	else
		t_nfb = max(hc->tx_t_rto, 2 * hc->tx_t_ipi);

restart_timer:
	sk_reset_timer(sk, &hc->tx_no_feedback_timer,
			   jiffies + usecs_to_jiffies(t_nfb));
out:
	bh_unlock_sock(sk);
	sock_put(sk);
}


static u32 ccid3_first_li(struct sock *sk)
{
	struct ccid3_hc_rx_sock *hc = ccid3_hc_rx_sk(sk);
	u32 x_recv, p, delta;
	u64 fval;

	if (hc->rx_rtt == 0) {
		DCCP_WARN("No RTT estimate available, using fallback RTT\n");
		hc->rx_rtt = DCCP_FALLBACK_RTT;
	}

	delta  = ktime_to_us(net_timedelta(hc->rx_tstamp_last_feedback));
	x_recv = scaled_div32(hc->rx_bytes_recv, delta);
	if (x_recv == 0) {		/* would also trigger divide-by-zero */
		DCCP_WARN("X_recv==0\n");
		if (hc->rx_x_recv == 0) {
			DCCP_BUG("stored value of X_recv is zero");
			return ~0U;
		}
		x_recv = hc->rx_x_recv;
	}

	fval = scaled_div(hc->rx_s, hc->rx_rtt);
	fval = scaled_div32(fval, x_recv);
	p = tfrc_calc_x_reverse_lookup(fval);

	ccid3_pr_debug("%s(%p), receive rate=%u bytes/s, implied "
		       "loss rate=%u\n", dccp_role(sk), sk, x_recv, p);

	return p == 0 ? ~0U : scaled_div(1, p);
}


static void ccid3_hc_tx_get_info(struct sock *sk, struct tcp_info *info)
{
	info->tcpi_rto = ccid3_hc_tx_sk(sk)->tx_t_rto;
	info->tcpi_rtt = ccid3_hc_tx_sk(sk)->tx_rtt;
}


void edge_filtering_chroma_internal(de265_image* img, bool vertical,
                                    int yStart,int yEnd,
                                    int xStart,int xEnd)
{
  //printf("chroma %d-%d %d-%d\n",xStart,xEnd,yStart,yEnd);

  const seq_parameter_set& sps = img->get_sps();

  const int SubWidthC  = sps.SubWidthC;
  const int SubHeightC = sps.SubHeightC;

  int xIncr = vertical ? 2 : 1;
  int yIncr = vertical ? 1 : 2;

  xIncr *= SubWidthC;
  yIncr *= SubHeightC;

  const int stride = img->get_image_stride(1);

  xEnd = libde265_min(xEnd,img->get_deblk_width());
  yEnd = libde265_min(yEnd,img->get_deblk_height());

  int bitDepth_C = sps.BitDepth_C;

  for (int y=yStart;y<yEnd;y+=yIncr)
    for (int x=xStart;x<xEnd;x+=xIncr) {
      int xDi = x << (3-SubWidthC);
      int yDi = y << (3-SubHeightC);

      //printf("x,y:%d,%d  xDi,yDi:%d,%d\n",x,y,xDi,yDi);

      int bS = img->get_deblk_bS(xDi*SubWidthC,yDi*SubHeightC);

      if (bS>1) {
        // 8.7.2.4.5

        for (int cplane=0;cplane<2;cplane++) {
          int cQpPicOffset = (cplane==0 ?
                              img->get_pps().pic_cb_qp_offset :
                              img->get_pps().pic_cr_qp_offset);

          pixel_t* ptr = img->get_image_plane_at_pos_NEW<pixel_t>(cplane+1, xDi,yDi);

          pixel_t p[2][4];
          pixel_t q[2][4];

          logtrace(LogDeblock,"-%s- %d %d\n",cplane==0 ? "Cb" : "Cr",xDi,yDi);

          for (int i=0;i<2;i++)
            for (int k=0;k<4;k++)
              {
                if (vertical) {
                  q[i][k] = ptr[ i  +k*stride];
                  p[i][k] = ptr[-i-1+k*stride];
                }
                else {
                  q[i][k] = ptr[k + i   *stride];
                  p[i][k] = ptr[k -(i+1)*stride];
                }
              }

#if 0
          for (int k=0;k<4;k++)
            {
              for (int i=0;i<2;i++)
                {
                  printf("%02x ", p[1-i][k]);
                }

              printf("| ");

              for (int i=0;i<2;i++)
                {
                  printf("%02x ", q[i][k]);
                }
              printf("\n");
            }
#endif

          int QP_Q = img->get_QPY(SubWidthC*xDi,SubHeightC*yDi);
          int QP_P = (vertical ?
                      img->get_QPY(SubWidthC*xDi-1,SubHeightC*yDi) :
                      img->get_QPY(SubWidthC*xDi,SubHeightC*yDi-1));
          int qP_i = ((QP_Q+QP_P+1)>>1) + cQpPicOffset;
          int QP_C;
          if (sps.ChromaArrayType == CHROMA_420) {
            QP_C = table8_22(qP_i);
          } else {
            QP_C = libde265_min(qP_i, 51);
          }

          //printf("POC=%d\n",ctx->img->PicOrderCntVal);
          logtrace(LogDeblock,"%d %d: ((%d+%d+1)>>1) + %d = qP_i=%d  (QP_C=%d)\n",
                   SubWidthC*xDi,SubHeightC*yDi, QP_Q,QP_P,cQpPicOffset,qP_i,QP_C);

          int sliceIndexQ00 = img->get_SliceHeaderIndex(SubWidthC*xDi,SubHeightC*yDi);
          int tc_offset   = img->slices[sliceIndexQ00]->slice_tc_offset;

          int Q = Clip3(0,53, QP_C + 2*(bS-1) + tc_offset);

          int tcPrime = table_8_23_tc[Q];
          int tc = tcPrime * (1<<(sps.BitDepth_C - 8));

          logtrace(LogDeblock,"tc_offset=%d Q=%d tc'=%d tc=%d\n",tc_offset,Q,tcPrime,tc);

          if (vertical) {
            bool filterP = true;
            if (sps.pcm_loop_filter_disable_flag && img->get_pcm_flag(SubWidthC*xDi-1,SubHeightC*yDi)) filterP=false;
            if (img->get_cu_transquant_bypass(SubWidthC*xDi-1,SubHeightC*yDi)) filterP=false;

            bool filterQ = true;
            if (sps.pcm_loop_filter_disable_flag && img->get_pcm_flag(SubWidthC*xDi,SubHeightC*yDi)) filterQ=false;
            if (img->get_cu_transquant_bypass(SubWidthC*xDi,SubHeightC*yDi)) filterQ=false;

            for (int k=0;k<4;k++) {
              int delta = Clip3(-tc,tc, ((((q[0][k]-p[0][k])*4)+p[1][k]-q[1][k]+4)>>3)); // standard says <<2 in eq. (8-356), but the value can also be negative
              logtrace(LogDeblock,"delta=%d\n",delta);
              if (filterP) { ptr[-1+k*stride] = Clip_BitDepth(p[0][k]+delta, bitDepth_C); }
              if (filterQ) { ptr[ 0+k*stride] = Clip_BitDepth(q[0][k]-delta, bitDepth_C); }
            }
          }
          else {
            bool filterP = true;
            if (sps.pcm_loop_filter_disable_flag && img->get_pcm_flag(SubWidthC*xDi,SubHeightC*yDi-1)) filterP=false;
            if (img->get_cu_transquant_bypass(SubWidthC*xDi,SubHeightC*yDi-1)) filterP=false;

            bool filterQ = true;
            if (sps.pcm_loop_filter_disable_flag && img->get_pcm_flag(SubWidthC*xDi,SubHeightC*yDi)) filterQ=false;
            if (img->get_cu_transquant_bypass(SubWidthC*xDi,SubHeightC*yDi)) filterQ=false;

            for (int k=0;k<4;k++) {
              int delta = Clip3(-tc,tc, ((((q[0][k]-p[0][k])*4)+p[1][k]-q[1][k]+4)>>3)); // standard says <<2, but the value can also be negative
              if (filterP) { ptr[ k-1*stride] = Clip_BitDepth(p[0][k]+delta, bitDepth_C); }
              if (filterQ) { ptr[ k+0*stride] = Clip_BitDepth(q[0][k]-delta, bitDepth_C); }
            }
          }
        }
      }
    }
}


void derive_boundaryStrength_CTB(de265_image* img, bool vertical, int xCtb,int yCtb)
{
  int ctbSize = img->get_sps().CtbSizeY;
  int deblkSize = ctbSize/4;

  derive_boundaryStrength(img,vertical,
                          yCtb*deblkSize, (yCtb+1)*deblkSize,
                          xCtb*deblkSize, (xCtb+1)*deblkSize);
}


fst_remove_one(struct pci_dev *pdev)
{
	struct fst_card_info *card;
	int i;

	card = pci_get_drvdata(pdev);

	for (i = 0; i < card->nports; i++) {
		struct net_device *dev = port_to_dev(&card->ports[i]);
		unregister_hdlc_device(dev);
	}

	fst_disable_intr(card);
	free_irq(card->irq, card);

	iounmap(card->ctlmem);
	iounmap(card->mem);
	pci_release_regions(pdev);
	if (card->family == FST_FAMILY_TXU) {
		/*
		 * Free dma buffers
		 */
		pci_free_consistent(card->device, FST_MAX_MTU,
				    card->rx_dma_handle_host,
				    card->rx_dma_handle_card);
		pci_free_consistent(card->device, FST_MAX_MTU,
				    card->tx_dma_handle_host,
				    card->tx_dma_handle_card);
	}
	fst_card_array[card->card_no] = NULL;
}


fst_init_dma(struct fst_card_info *card)
{
	/*
	 * This is only required for the PLX 9054
	 */
	if (card->family == FST_FAMILY_TXU) {
	        pci_set_master(card->device);
		outl(0x00020441, card->pci_conf + DMAMODE0);
		outl(0x00020441, card->pci_conf + DMAMODE1);
		outl(0x0, card->pci_conf + DMATHR);
	}
}


fst_intr_ctlchg(struct fst_card_info *card, struct fst_port_info *port)
{
	int signals;

	signals = FST_RDL(card, v24DebouncedSts[port->index]);

	if (signals & (((port->hwif == X21) || (port->hwif == X21D))
		       ? IPSTS_INDICATE : IPSTS_DCD)) {
		if (!netif_carrier_ok(port_to_dev(port))) {
			dbg(DBG_INTR, "DCD active\n");
			netif_carrier_on(port_to_dev(port));
		}
	} else {
		if (netif_carrier_ok(port_to_dev(port))) {
			dbg(DBG_INTR, "DCD lost\n");
			netif_carrier_off(port_to_dev(port));
		}
	}
}


fst_q_work_item(u64 * queue, int card_index)
{
	unsigned long flags;
	u64 mask;

	/*
	 * Grab the queue exclusively
	 */
	spin_lock_irqsave(&fst_work_q_lock, flags);

	/*
	 * Making an entry in the queue is simply a matter of setting
	 * a bit for the card indicating that there is work to do in the
	 * bottom half for the card.  Note the limitation of 64 cards.
	 * That ought to be enough
	 */
	mask = (u64)1 << card_index;
	*queue |= mask;
	spin_unlock_irqrestore(&fst_work_q_lock, flags);
}


fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
		    int len, struct sk_buff *skb, int rxp)
{
	struct net_device *dev = port_to_dev(port);
	int pi;
	int rx_status;

	dbg(DBG_TX, "fst_rx_dma_complete\n");
	pi = port->index;
	memcpy(skb_put(skb, len), card->rx_dma_handle_host, len);

	/* Reset buffer descriptor */
	FST_WRB(card, rxDescrRing[pi][rxp].bits, DMA_OWN);

	/* Update stats */
	dev->stats.rx_packets++;
	dev->stats.rx_bytes += len;

	/* Push upstream */
	dbg(DBG_RX, "Pushing the frame up the stack\n");
	if (port->mode == FST_RAW)
		skb->protocol = farsync_type_trans(skb, dev);
	else
		skb->protocol = hdlc_type_trans(skb, dev);
	rx_status = netif_rx(skb);
	fst_process_rx_status(rx_status, port_to_dev(port)->name);
	if (rx_status == NET_RX_DROP)
		dev->stats.rx_dropped++;
}


static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev)
{
	skb->dev = dev;
	skb_reset_mac_header(skb);
	skb->pkt_type = PACKET_HOST;
	return htons(ETH_P_CUST);
}


const PBMotion& get_mv_info(int x,int y) const override { return img->get_mv_info(x,y); }


write_uint32_le(ds_file_t *file, ulong n)
{
	char tmp[4];

	int4store(tmp, n);
	return ds_write(file, tmp, sizeof(tmp));
}


void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
  if (!owner_window_)
    return;

  SetHtmlApiFullscreen(false);

  if (native_fullscreen_) {
    // Explicitly trigger a view resize, as the size is not actually changing if
    // the browser is fullscreened, too. Chrome does this indirectly from
    // `chrome/browser/ui/exclusive_access/fullscreen_controller.cc`.
    source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
  }
}


void ElectronBrowserClient::OverrideURLLoaderFactoryParams(
    content::BrowserContext* browser_context,
    const url::Origin& origin,
    bool is_for_isolated_world,
    network::mojom::URLLoaderFactoryParams* factory_params) {
  if (factory_params->top_frame_id) {
    // Bypass CORB and CORS when web security is disabled.
    auto* rfh = content::RenderFrameHost::FromFrameToken(
        factory_params->process_id,
        blink::LocalFrameToken(factory_params->top_frame_id.value()));
    auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
    auto* prefs = WebContentsPreferences::From(web_contents);
    if (prefs && !prefs->IsEnabled(options::kWebSecurity, true)) {
      factory_params->is_corb_enabled = false;
      factory_params->disable_web_security = true;
    }
  }

  extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
      browser_context, origin, is_for_isolated_world, factory_params);
}


bool ElectronBrowserClient::BindAssociatedReceiverFromFrame(
    content::RenderFrameHost* render_frame_host,
    const std::string& interface_name,
    mojo::ScopedInterfaceEndpointHandle* handle) {
  if (interface_name == mojom::ElectronAutofillDriver::Name_) {
    AutofillDriverFactory::BindAutofillDriver(
        mojom::ElectronAutofillDriverAssociatedRequest(std::move(*handle)),
        render_frame_host);
    return true;
  }
  if (interface_name == electron::mojom::ElectronApiIPC::Name_) {
    return BindElectronApiIPC(
        mojo::PendingAssociatedReceiver<electron::mojom::ElectronApiIPC>(
            std::move(*handle)),
        render_frame_host);
  }

  if (interface_name == electron::mojom::ElectronWebContentsUtility::Name_) {
    BindElectronWebContentsUtility(
        mojo::PendingAssociatedReceiver<
            electron::mojom::ElectronWebContentsUtility>(std::move(*handle)),
        render_frame_host);
    return true;
  }

#if BUILDFLAG(ENABLE_PRINTING)
  if (interface_name == printing::mojom::PrintManagerHost::Name_) {
    mojo::PendingAssociatedReceiver<printing::mojom::PrintManagerHost> receiver(
        std::move(*handle));
    PrintViewManagerElectron::BindPrintManagerHost(std::move(receiver),
                                                   render_frame_host);
    return true;
  }
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
  if (interface_name == extensions::mojom::LocalFrameHost::Name_) {
    extensions::ExtensionWebContentsObserver::BindLocalFrameHost(
        mojo::PendingAssociatedReceiver<extensions::mojom::LocalFrameHost>(
            std::move(*handle)),
        render_frame_host);
    return true;
  }
#endif

  return false;
}


vbf_fetch_thread(struct worker *wrk, void *priv)
{
	struct busyobj *bo;
	enum fetch_step stp;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CAST_OBJ_NOTNULL(bo, priv, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->fetch_objcore, OBJCORE_MAGIC);

	THR_SetBusyobj(bo);
	stp = F_STP_MKBEREQ;
	assert(isnan(bo->t_first));
	assert(isnan(bo->t_prev));
	VSLb_ts_busyobj(bo, "Start", W_TIM_real(wrk));

	bo->wrk = wrk;
	wrk->vsl = bo->vsl;

#if 0
	if (bo->stale_oc != NULL) {
		CHECK_OBJ_NOTNULL(bo->stale_oc, OBJCORE_MAGIC);
		/* We don't want the oc/stevedore ops in fetching thread */
		if (!ObjCheckFlag(wrk, bo->stale_oc, OF_IMSCAND))
			(void)HSH_DerefObjCore(wrk, &bo->stale_oc, 0);
	}
#endif

	while (stp != F_STP_DONE) {
		CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
		assert(bo->fetch_objcore->boc->refcount >= 1);
		switch (stp) {
#define FETCH_STEP(l, U, arg)						\
		case F_STP_##U:						\
			stp = vbf_stp_##l arg;				\
			break;
#include "tbl/steps.h"
		default:
			WRONG("Illegal fetch_step");
		}
	}

	assert(bo->director_state == DIR_S_NULL);

	http_Teardown(bo->bereq);
	http_Teardown(bo->beresp);

	if (bo->fetch_objcore->boc->state == BOS_FINISHED) {
		AZ(bo->fetch_objcore->flags & OC_F_FAILED);
		VSLb(bo->vsl, SLT_Length, "%ju",
		    (uintmax_t)ObjGetLen(bo->wrk, bo->fetch_objcore));
	}
	// AZ(bo->fetch_objcore->boc);	// XXX

	if (bo->stale_oc != NULL)
		(void)HSH_DerefObjCore(wrk, &bo->stale_oc, 0);

	wrk->vsl = NULL;
	HSH_DerefBoc(wrk, bo->fetch_objcore);
	SES_Rel(bo->sp);
	VBO_ReleaseBusyObj(wrk, &bo);
	THR_SetBusyobj(NULL);
}


vbf_stp_fetchend(struct worker *wrk, struct busyobj *bo)
{

	AZ(bo->vfc->failed);
	VFP_Close(bo->vfc);

	AZ(ObjSetU64(wrk, bo->fetch_objcore, OA_LEN,
	    bo->fetch_objcore->boc->len_so_far));

	if (bo->do_stream)
		assert(bo->fetch_objcore->boc->state == BOS_STREAM);
	else {
		assert(bo->fetch_objcore->boc->state == BOS_REQ_DONE);
		HSH_Unbusy(wrk, bo->fetch_objcore);
	}

	/* Recycle the backend connection before setting BOS_FINISHED to
	   give predictable backend reuse behavior for varnishtest */
	VDI_Finish(bo->wrk, bo);

	ObjSetState(wrk, bo->fetch_objcore, BOS_FINISHED);
	VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk));
	if (bo->stale_oc != NULL)
		HSH_Kill(bo->stale_oc);
	return (F_STP_DONE);
}


vbf_objiterator(void *priv, int flush, const void *ptr, ssize_t len)
{
	struct busyobj *bo;
	ssize_t l;
	const uint8_t *ps = ptr;
	uint8_t *pd;

	(void)flush;
	CAST_OBJ_NOTNULL(bo, priv, BUSYOBJ_MAGIC);

	while (len > 0) {
		l = len;
		if (VFP_GetStorage(bo->vfc, &l, &pd) != VFP_OK)
			return (1);
		if (len < l)
			l = len;
		memcpy(pd, ps, l);
		VFP_Extend(bo->vfc, l);
		ps += l;
		len -= l;
	}
	return (0);
}


vbf_stp_done(void)
{
	WRONG("Just plain wrong");
	NEEDLESS(return(F_STP_DONE));
}


MagickExport MagickBooleanType WriteImage(const ImageInfo *image_info,
  Image *image,ExceptionInfo *exception)
{
  char
    filename[MagickPathExtent];

  const char
    *option;

  const DelegateInfo
    *delegate_info;

  const MagickInfo
    *magick_info;

  ExceptionInfo
    *sans_exception;

  ImageInfo
    *write_info;

  MagickBooleanType
    status,
    temporary;

  PolicyDomain
    domain;

  PolicyRights
    rights;

  /*
    Determine image type from filename prefix or suffix (e.g. image.jpg).
  */
  assert(image_info != (ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  if (image->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",
      image_info->filename);
  assert(image != (Image *) NULL);
  assert(image->signature == MagickCoreSignature);
  assert(exception != (ExceptionInfo *) NULL);
  sans_exception=AcquireExceptionInfo();
  write_info=CloneImageInfo(image_info);
  (void) CopyMagickString(write_info->filename,image->filename,MagickPathExtent);
  (void) SetImageInfo(write_info,1,sans_exception);
  if (*write_info->magick == '\0')
    (void) CopyMagickString(write_info->magick,image->magick,MagickPathExtent);
  (void) CopyMagickString(filename,image->filename,MagickPathExtent);
  (void) CopyMagickString(image->filename,write_info->filename,MagickPathExtent);
  domain=CoderPolicyDomain;
  rights=WritePolicyRights;
  if (IsRightsAuthorized(domain,rights,write_info->magick) == MagickFalse)
    {
      sans_exception=DestroyExceptionInfo(sans_exception);
      write_info=DestroyImageInfo(write_info);
      errno=EPERM;
      ThrowBinaryException(PolicyError,"NotAuthorized",filename);
    }
  /*
    Call appropriate image reader based on image type.
  */
  magick_info=GetMagickInfo(write_info->magick,sans_exception);
  sans_exception=DestroyExceptionInfo(sans_exception);
  if (magick_info != (const MagickInfo *) NULL)
    {
      if (GetMagickEndianSupport(magick_info) == MagickFalse)
        image->endian=UndefinedEndian;
      else
        if ((image_info->endian == UndefinedEndian) &&
            (GetMagickRawSupport(magick_info) != MagickFalse))
          {
            unsigned long
              lsb_first;

            lsb_first=1;
            image->endian=(*(char *) &lsb_first) == 1 ? LSBEndian : MSBEndian;
         }
    }
  (void) SyncImageProfiles(image);
  DisassociateImageStream(image);
  option=GetImageOption(image_info,"delegate:bimodal");
  if ((IfMagickTrue(IsStringTrue(option))) &&
      (write_info->page == (char *) NULL) &&
      (GetPreviousImageInList(image) == (Image *) NULL) &&
      (GetNextImageInList(image) == (Image *) NULL) &&
      (IfMagickFalse(IsTaintImage(image))) )
    {
      delegate_info=GetDelegateInfo(image->magick,write_info->magick,exception);
      if ((delegate_info != (const DelegateInfo *) NULL) &&
          (GetDelegateMode(delegate_info) == 0) &&
          (IsPathAccessible(image->magick_filename) != MagickFalse))
        {
          /*
            Process image with bi-modal delegate.
          */
          (void) CopyMagickString(image->filename,image->magick_filename,
            MagickPathExtent);
          status=InvokeDelegate(write_info,image,image->magick,
            write_info->magick,exception);
          write_info=DestroyImageInfo(write_info);
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
          return(status);
        }
    }
  status=MagickFalse;
  temporary=MagickFalse;
  if ((magick_info != (const MagickInfo *) NULL) &&
      (GetMagickSeekableStream(magick_info) != MagickFalse))
    {
      char
        image_filename[MagickPathExtent];

      (void) CopyMagickString(image_filename,image->filename,MagickPathExtent);
      status=OpenBlob(image_info,image,WriteBinaryBlobMode,exception);
      (void) CopyMagickString(image->filename, image_filename,MagickPathExtent);
      if (status != MagickFalse)
        {
          if (IsBlobSeekable(image) == MagickFalse)
            {
              /*
                A seekable stream is required by the encoder.
              */
              write_info->adjoin=MagickTrue;
              (void) CopyMagickString(write_info->filename,image->filename,
                MagickPathExtent);
              (void) AcquireUniqueFilename(image->filename);
              temporary=MagickTrue;
            }
          (void) CloseBlob(image);
        }
    }
  if ((magick_info != (const MagickInfo *) NULL) &&
      (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL))
    {
      /*
        Call appropriate image writer based on image type.
      */
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
        LockSemaphoreInfo(magick_info->semaphore);
      status=GetImageEncoder(magick_info)(write_info,image,exception);
      if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
        UnlockSemaphoreInfo(magick_info->semaphore);
    }
  else
    {
      delegate_info=GetDelegateInfo((char *) NULL,write_info->magick,exception);
      if (delegate_info != (DelegateInfo *) NULL)
        {
          /*
            Process the image with delegate.
          */
          *write_info->filename='\0';
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
            LockSemaphoreInfo(delegate_info->semaphore);
          status=InvokeDelegate(write_info,image,(char *) NULL,
            write_info->magick,exception);
          if (GetDelegateThreadSupport(delegate_info) == MagickFalse)
            UnlockSemaphoreInfo(delegate_info->semaphore);
          (void) CopyMagickString(image->filename,filename,MagickPathExtent);
        }
      else
        {
          sans_exception=AcquireExceptionInfo();
          magick_info=GetMagickInfo(write_info->magick,sans_exception);
          sans_exception=DestroyExceptionInfo(sans_exception);
          if ((write_info->affirm == MagickFalse) &&
              (magick_info == (const MagickInfo *) NULL))
            {
              (void) CopyMagickString(write_info->magick,image->magick,
                MagickPathExtent);
              magick_info=GetMagickInfo(write_info->magick,exception);
            }
          if ((magick_info == (const MagickInfo *) NULL) ||
              (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL))
            {
              char
                extension[MagickPathExtent];

              GetPathComponent(image->filename,ExtensionPath,extension);
              if (*extension != '\0')
                magick_info=GetMagickInfo(extension,exception);
              else
                magick_info=GetMagickInfo(image->magick,exception);
              (void) CopyMagickString(image->filename,filename,MagickPathExtent);
            }
          if ((magick_info == (const MagickInfo *) NULL) ||
              (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL))
            {
              magick_info=GetMagickInfo(image->magick,exception);
              if ((magick_info == (const MagickInfo *) NULL) ||
                  (GetImageEncoder(magick_info) == (EncodeImageHandler *) NULL))
                (void) ThrowMagickException(exception,GetMagickModule(),
                  MissingDelegateError,"NoEncodeDelegateForThisImageFormat",
                  "`%s'",write_info->magick);
              else
                (void) ThrowMagickException(exception,GetMagickModule(),
                  MissingDelegateWarning,"NoEncodeDelegateForThisImageFormat",
                  "`%s'",write_info->magick);
            }
          if ((magick_info != (const MagickInfo *) NULL) &&
              (GetImageEncoder(magick_info) != (EncodeImageHandler *) NULL))
            {
              /*
                Call appropriate image writer based on image type.
              */
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
                LockSemaphoreInfo(magick_info->semaphore);
              status=GetImageEncoder(magick_info)(write_info,image,exception);
              if (GetMagickEncoderThreadSupport(magick_info) == MagickFalse)
                UnlockSemaphoreInfo(magick_info->semaphore);
            }
        }
    }
  if (temporary != MagickFalse)
    {
      /*
        Copy temporary image file to permanent.
      */
      status=OpenBlob(write_info,image,ReadBinaryBlobMode,exception);
      if (status != MagickFalse)
        {
          (void) RelinquishUniqueFileResource(write_info->filename);
          status=ImageToFile(image,write_info->filename,exception);
        }
      (void) CloseBlob(image);
      (void) RelinquishUniqueFileResource(image->filename);
      (void) CopyMagickString(image->filename,write_info->filename,
        MagickPathExtent);
    }
  if ((LocaleCompare(write_info->magick,"info") != 0) &&
      (write_info->verbose != MagickFalse))
    (void) IdentifyImage(image,stdout,MagickFalse,exception);
  write_info=DestroyImageInfo(write_info);
  return(status);
}


MagickExport MagickBooleanType WriteImages(const ImageInfo *image_info,
  Image *images,const char *filename,ExceptionInfo *exception)
{
#define WriteImageTag  "Write/Image"

  ExceptionInfo
    *sans_exception;

  ImageInfo
    *write_info;

  MagickBooleanType
    proceed;

  MagickOffsetType
    progress;

  MagickProgressMonitor
    progress_monitor;

  MagickSizeType
    number_images;

  MagickStatusType
    status;

  register Image
    *p;

  assert(image_info != (const ImageInfo *) NULL);
  assert(image_info->signature == MagickCoreSignature);
  assert(images != (Image *) NULL);
  assert(images->signature == MagickCoreSignature);
  if (images->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",images->filename);
  assert(exception != (ExceptionInfo *) NULL);
  write_info=CloneImageInfo(image_info);
  *write_info->magick='\0';
  images=GetFirstImageInList(images);
  if (filename != (const char *) NULL)
    for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
      (void) CopyMagickString(p->filename,filename,MagickPathExtent);
  (void) CopyMagickString(write_info->filename,images->filename,MagickPathExtent);
  sans_exception=AcquireExceptionInfo();
  (void) SetImageInfo(write_info,(unsigned int) GetImageListLength(images),
    sans_exception);
  sans_exception=DestroyExceptionInfo(sans_exception);
  if (*write_info->magick == '\0')
    (void) CopyMagickString(write_info->magick,images->magick,MagickPathExtent);
  p=images;
  for ( ; GetNextImageInList(p) != (Image *) NULL; p=GetNextImageInList(p))
  {
    register Image
      *next;

    next=GetNextImageInList(p);
    if (next == (Image *) NULL)
      break;
    if (p->scene >= next->scene)
      {
        register ssize_t
          i;

        /*
          Generate consistent scene numbers.
        */
        i=(ssize_t) images->scene;
        for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
          p->scene=(size_t) i++;
        break;
      }
  }
  /*
    Write images.
  */
  status=MagickTrue;
  progress_monitor=(MagickProgressMonitor) NULL;
  progress=0;
  number_images=GetImageListLength(images);
  for (p=images; p != (Image *) NULL; p=GetNextImageInList(p))
  {
    if (number_images != 1)
      progress_monitor=SetImageProgressMonitor(p,(MagickProgressMonitor) NULL,
        p->client_data);
    status&=WriteImage(write_info,p,exception);
    if (number_images != 1)
      (void) SetImageProgressMonitor(p,progress_monitor,p->client_data);
    if (write_info->adjoin != MagickFalse)
      break;
    if (number_images != 1)
      {
        proceed=SetImageProgress(p,WriteImageTag,progress++,number_images);
        if (proceed == MagickFalse)
          break;
      }
  }
  write_info=DestroyImageInfo(write_info);
  return(status != 0 ? MagickTrue : MagickFalse);
}


bool r_pkcs7_parse_signerinfos (RPKCS7SignerInfos *ss, RASN1Object *object) {
	ut32 i;
	if (!ss && !object) {
		return false;
	}
	if (object->list.length > 0) {
		ss->elements = (RPKCS7SignerInfo **) calloc (object->list.length, sizeof (RPKCS7SignerInfo*));
		if (!ss->elements) {
			return false;
		}
		ss->length = object->list.length;
		for (i = 0; i < ss->length; ++i) {
			// r_pkcs7_parse_signerinfo returns bool,
			// so i have to allocate before calling the function
			ss->elements[i] = R_NEW0 (RPKCS7SignerInfo);
			//should i handle invalid memory? the function checks the pointer
			//or it should return if si->elements[i] == NULL ?
			r_pkcs7_parse_signerinfo (ss->elements[i], object->list.objects[i]);
		}
	}
	return true;
}


void r_pkcs7_free_issuerandserialnumber (RPKCS7IssuerAndSerialNumber* iasu) {
	if (iasu) {
		r_x509_free_name (&iasu->issuer);
		r_asn1_free_object (iasu->serialNumber);
		// Used internally pkcs #7, so it should't free iasu.
	}
}


char *r_pkcs7_cms_dump (RCMS* container) {
	RPKCS7SignedData *sd;
	ut32 i, length, p = 0;
	int r;
	char *buffer = NULL, *tmp = NULL;
	if (!container) {
		return NULL;
	}
	sd = &container->signedData;
	length = 2048 + (container->signedData.certificates.length * 1024);
	if(!length) {
		return NULL;
	}
	buffer = (char*) calloc (1, length);
	if (!buffer) {
		return NULL;
	}
	r = snprintf (buffer, length, "signedData\n  Version: %u\n  Digest Algorithms:\n", sd->version);
	p += (ut32) r;
	if (r < 0 || length <= p) {
		free (buffer);
		return NULL;
	}
	if (container->signedData.digestAlgorithms.elements) {
		for (i = 0; i < container->signedData.digestAlgorithms.length; ++i) {
			if (container->signedData.digestAlgorithms.elements[i]) {
				RASN1String *s = container->signedData.digestAlgorithms.elements[i]->algorithm;
				r = snprintf (buffer + p, length - p, "    %s\n", s ? s->string : "Missing");
				p += (ut32) r;
				if (r < 0 || length <= p) {
					free (buffer);
					return NULL;
				}
			}
		}
	}
	r = snprintf (buffer + p, length - p, "  Certificates: %u\n", container->signedData.certificates.length);
	p += (ut32) r;
	if (r < 0 || length <= p) {
		free (buffer);
		return NULL;
	}
	for (i = 0; i < container->signedData.certificates.length; ++i) {
		if (length <= p || !(tmp = r_x509_certificate_dump (container->signedData.certificates.elements[i], buffer + p, length - p, "    "))) {
			free (buffer);
			return NULL;
		}
		p = tmp - buffer;
	}

	for (i = 0; i < container->signedData.crls.length; ++i) {
		if (length <= p || !(tmp = r_x509_crl_dump (container->signedData.crls.elements[i], buffer + p, length - p, "    "))) {
			free (buffer);
			return NULL;
		}
		p = tmp - buffer;
	}
	p = tmp - buffer;
	if (length <= p) {
		free (buffer);
		return NULL;
	}
	r = snprintf (buffer + p, length - p, "  SignerInfos:\n");
	p += (ut32) r;
	if (r < 0 || length <= p) {
		free (buffer);
		return NULL;
	}
	if (container->signedData.signerinfos.elements) {
		for (i = 0; i < container->signedData.signerinfos.length; ++i) {
			if (length <= p || !(tmp = r_x509_signedinfo_dump (container->signedData.signerinfos.elements[i], buffer + p, length - p, "    "))) {
				free (buffer);
				return NULL;
			}
			p = tmp - buffer;
		}
	}
	return buffer;
}


static void show_elfs(struct user_ta_ctx *utc)
{
	struct user_ta_elf *elf;
	size_t __maybe_unused idx = 0;

	TAILQ_FOREACH(elf, &utc->elfs, link)
		EMSG_RAW(" [%zu] %pUl @ %#" PRIxVA, idx++,
			 (void *)&elf->uuid, elf->load_addr);
}


static TEE_Result add_deps(struct user_ta_ctx *utc __unused,
			   struct elf_load_state *state __unused,
			   vaddr_t load_addr __unused)
{
	return TEE_SUCCESS;
}


static TEE_Result set_exidx(struct user_ta_ctx *utc __unused)
{
	return TEE_SUCCESS;
}


static TEE_Result resolve_symbol(struct user_ta_elf_head *elfs,
				 const char *name, uintptr_t *val)
{
	struct user_ta_elf *elf;
	TEE_Result res;

	/*
	 * The loop naturally implements a breadth first search due to the
	 * order in which the libraries were added.
	 */
	TAILQ_FOREACH(elf, elfs, link) {
		res = elf_resolve_symbol(elf->elf_state, name, val);
		if (res == TEE_ERROR_ITEM_NOT_FOUND)
			continue;
		if (res)
			return res;
		*val += elf->load_addr;
		FMSG("%pUl/0x%" PRIxPTR " %s", (void *)&elf->uuid, *val, name);
		return TEE_SUCCESS;
	}

	return TEE_ERROR_ITEM_NOT_FOUND;
}


void DoNonMaxSuppressionOp(OpKernelContext* context, const Tensor& scores,
                           int num_boxes, const Tensor& max_output_size,
                           const T similarity_threshold,
                           const T score_threshold, const T soft_nms_sigma,
                           const std::function<float(int, int)>& similarity_fn,
                           bool return_scores_tensor = false,
                           bool pad_to_max_output_size = false,
                           int* ptr_num_valid_outputs = nullptr) {
  const int output_size = max_output_size.scalar<int>()();
  OP_REQUIRES(context, output_size >= 0,
              errors::InvalidArgument("output size must be non-negative"));

  std::vector<T> scores_data(num_boxes);
  std::copy_n(scores.flat<T>().data(), num_boxes, scores_data.begin());

  // Data structure for a selection candidate in NMS.
  struct Candidate {
    int box_index;
    T score;
    int suppress_begin_index;
  };

  auto cmp = [](const Candidate bs_i, const Candidate bs_j) {
    return ((bs_i.score == bs_j.score) && (bs_i.box_index > bs_j.box_index)) ||
           bs_i.score < bs_j.score;
  };
  std::priority_queue<Candidate, std::deque<Candidate>, decltype(cmp)>
      candidate_priority_queue(cmp);
  for (int i = 0; i < scores_data.size(); ++i) {
    if (scores_data[i] > score_threshold) {
      candidate_priority_queue.emplace(Candidate({i, scores_data[i], 0}));
    }
  }

  T scale = static_cast<T>(0.0);
  bool is_soft_nms = soft_nms_sigma > static_cast<T>(0.0);
  if (is_soft_nms) {
    scale = static_cast<T>(-0.5) / soft_nms_sigma;
  }

  auto suppress_weight = [similarity_threshold, scale,
                          is_soft_nms](const T sim) {
    const T weight = Eigen::numext::exp<T>(scale * sim * sim);
    return is_soft_nms || sim <= similarity_threshold ? weight
                                                      : static_cast<T>(0.0);
  };

  std::vector<int> selected;
  std::vector<T> selected_scores;
  float similarity;
  T original_score;
  Candidate next_candidate;

  while (selected.size() < output_size && !candidate_priority_queue.empty()) {
    next_candidate = candidate_priority_queue.top();
    original_score = next_candidate.score;
    candidate_priority_queue.pop();

    // Overlapping boxes are likely to have similar scores, therefore we
    // iterate through the previously selected boxes backwards in order to
    // see if `next_candidate` should be suppressed. We also enforce a property
    // that a candidate can be suppressed by another candidate no more than
    // once via `suppress_begin_index` which tracks which previously selected
    // boxes have already been compared against next_candidate prior to a given
    // iteration.  These previous selected boxes are then skipped over in the
    // following loop.
    bool should_hard_suppress = false;
    for (int j = static_cast<int>(selected.size()) - 1;
         j >= next_candidate.suppress_begin_index; --j) {
      similarity = similarity_fn(next_candidate.box_index, selected[j]);

      next_candidate.score *= suppress_weight(static_cast<T>(similarity));

      // First decide whether to perform hard suppression
      if (!is_soft_nms && static_cast<T>(similarity) > similarity_threshold) {
        should_hard_suppress = true;
        break;
      }

      // If next_candidate survives hard suppression, apply soft suppression
      if (next_candidate.score <= score_threshold) break;
    }
    // If `next_candidate.score` has not dropped below `score_threshold`
    // by this point, then we know that we went through all of the previous
    // selections and can safely update `suppress_begin_index` to
    // `selected.size()`. If on the other hand `next_candidate.score`
    // *has* dropped below the score threshold, then since `suppress_weight`
    // always returns values in [0, 1], further suppression by items that were
    // not covered in the above for loop would not have caused the algorithm
    // to select this item. We thus do the same update to
    // `suppress_begin_index`, but really, this element will not be added back
    // into the priority queue in the following.
    next_candidate.suppress_begin_index = selected.size();

    if (!should_hard_suppress) {
      if (next_candidate.score == original_score) {
        // Suppression has not occurred, so select next_candidate
        selected.push_back(next_candidate.box_index);
        selected_scores.push_back(next_candidate.score);
        continue;
      }
      if (next_candidate.score > score_threshold) {
        // Soft suppression has occurred and current score is still greater than
        // score_threshold; add next_candidate back onto priority queue.
        candidate_priority_queue.push(next_candidate);
      }
    }
  }

  int num_valid_outputs = selected.size();
  if (pad_to_max_output_size) {
    selected.resize(output_size, 0);
    selected_scores.resize(output_size, static_cast<T>(0));
  }
  if (ptr_num_valid_outputs) {
    *ptr_num_valid_outputs = num_valid_outputs;
  }

  // Allocate output tensors
  Tensor* output_indices = nullptr;
  TensorShape output_shape({static_cast<int>(selected.size())});
  OP_REQUIRES_OK(context,
                 context->allocate_output(0, output_shape, &output_indices));
  TTypes<int, 1>::Tensor output_indices_data = output_indices->tensor<int, 1>();
  std::copy_n(selected.begin(), selected.size(), output_indices_data.data());

  if (return_scores_tensor) {
    Tensor* output_scores = nullptr;
    OP_REQUIRES_OK(context,
                   context->allocate_output(1, output_shape, &output_scores));
    typename TTypes<T, 1>::Tensor output_scores_data =
        output_scores->tensor<T, 1>();
    std::copy_n(selected_scores.begin(), selected_scores.size(),
                output_scores_data.data());
  }
}


static void CopyOutputBackpropRegion(const DepthwiseArgs& args,
                                     const int64_t padded_filter_inner_dim_size,
                                     const int64_t in_r, const int64_t in_c,
                                     const T* out_backprop, T* buffer) {
  typedef typename Eigen::internal::packet_traits<T>::type Packet;
  static const int64_t kPacketSize = (sizeof(Packet) / sizeof(T));

  const int64_t stride = args.stride;
  const int64_t filter_rows = args.filter_rows;
  const int64_t filter_cols = args.filter_cols;
  const int64_t pad_rows = args.pad_rows;
  const int64_t pad_cols = args.pad_cols;
  const int64_t out_rows = args.out_rows;
  const int64_t out_cols = args.out_cols;

  // Calculate the output spatial region which used point (in_r, in_c) as input.
  const int64_t out_r_start =
      std::max(static_cast<int64_t>(0),
               (in_r - filter_rows + pad_rows + stride) / stride);
  const int64_t out_r_end = std::min(out_rows - 1, (in_r + pad_rows) / stride);
  const int64_t out_c_start =
      std::max(static_cast<int64_t>(0),
               (in_c - filter_cols + pad_cols + stride) / stride);
  const int64_t out_c_end = std::min(out_cols - 1, (in_c + pad_cols) / stride);

  // Zero-pad 'buffer' if output region is smaller than filter spatial size.
  const int64_t filter_spatial_size = args.filter_rows * args.filter_cols;
  if ((out_r_end - out_r_start + 1) < args.filter_rows ||
      (out_c_end - out_c_start + 1) < args.filter_cols) {
    memset(buffer, 0,
           filter_spatial_size * padded_filter_inner_dim_size * sizeof(T));
  }

  // Calculate vectorized and scalar (residual) lengths for 'in_depth'.
  const int64_t vectorized_size = (args.out_depth / kPacketSize) * kPacketSize;
  const int64_t scalar_size = args.out_depth % kPacketSize;
  const int64_t pad_size = scalar_size > 0 ? kPacketSize - scalar_size : 0;

  for (int out_r = out_r_start; out_r <= out_r_end; ++out_r) {
    const int64_t f_r = in_r + pad_rows - out_r * stride;
    for (int out_c = out_c_start; out_c <= out_c_end; ++out_c) {
      const int64_t f_c = in_c + pad_cols - out_c * stride;
      const int64_t buf_base =
          (f_r * filter_cols + f_c) * padded_filter_inner_dim_size;
      // Calculate index into 'out_backprop' for coordinate (out_r, out_c).
      auto* out_bprop =
          out_backprop + (out_r * args.out_cols + out_c) * args.out_depth;

      // Copy vectorized portion of inner dimension into 'buffer'.
      for (int64_t d = 0; d < vectorized_size; d += kPacketSize) {
        auto v = Eigen::internal::ploadu<Packet>(out_bprop + d);
        Eigen::internal::pstoreu<T>(buffer + buf_base + d, v);
      }
      // Copy scalar portion of out_bprop to 'buffer'
      for (int64_t d = 0; d < scalar_size; ++d) {
        buffer[buf_base + vectorized_size + d] = out_bprop[vectorized_size + d];
      }
      // Pad to vector-register width (if needed).
      for (int64_t d = 0; d < pad_size; ++d) {
        buffer[buf_base + vectorized_size + scalar_size + d] =
            static_cast<T>(0);
      }
    }
  }
}


  void operator()(OpKernelContext* ctx, const DepthwiseArgs& args,
                  const T* out_backprop, const T* depthwise_filter,
                  T* in_backprop, TensorFormat data_format) {
    OP_REQUIRES(
        ctx, data_format == FORMAT_NHWC,
        errors::Unimplemented(
            "Depthwise convolution on CPU is only supported for NHWC format"));

    static const int64_t kPacketSize = (sizeof(Packet) / sizeof(T));

    // Pad 'depthwise_filter' to vector register width (if needed).
    const bool pad_filter = (args.out_depth % kPacketSize) == 0 ? false : true;
    Tensor padded_filter;
    if (pad_filter) {
      // Allocate space for padded filter.
      const int64_t filter_spatial_size = args.filter_rows * args.filter_cols;
      const int64_t padded_filter_inner_dim_size =
          ((args.out_depth + kPacketSize - 1) / kPacketSize) * kPacketSize;
      OP_REQUIRES_OK(
          ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                  TensorShape({filter_spatial_size,
                                               padded_filter_inner_dim_size}),
                                  &padded_filter));
      // Write out padded filter.
      functor::DepthwiseFilterPadOp<T>()(
          args, depthwise_filter, padded_filter.template flat<T>().data());
    }
    const T* filter_data =
        pad_filter ? padded_filter.template flat<T>().data() : depthwise_filter;

    // Computes one shard of depthwise conv2d backprop input.
    auto shard = [&ctx, &args, &out_backprop, &filter_data, &in_backprop](
                     int64_t start, int64_t limit) {
      static const int64_t kPacketSize = (sizeof(Packet) / sizeof(T));

      const int64_t input_image_size =
          args.in_rows * args.in_cols * args.in_depth;
      const int64_t output_image_size =
          args.out_rows * args.out_cols * args.out_depth;
      const int64_t filter_spatial_size = args.filter_rows * args.filter_cols;
      const int64_t padded_filter_inner_dim_size =
          ((args.out_depth + kPacketSize - 1) / kPacketSize) * kPacketSize;

      // Allocate buffer to copy regions from 'out_backprop'.
      Tensor out_bprop_buffer;
      OP_REQUIRES_OK(
          ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                  TensorShape({filter_spatial_size,
                                               padded_filter_inner_dim_size}),
                                  &out_bprop_buffer));
      T* out_bprop_buf = out_bprop_buffer.template flat<T>().data();

      // Allocate buffer for intermediate results.
      Tensor in_bprop_buffer;
      OP_REQUIRES_OK(
          ctx, ctx->allocate_temp(DataTypeToEnum<T>::value,
                                  TensorShape({padded_filter_inner_dim_size}),
                                  &in_bprop_buffer));
      T* in_bprop_buf = in_bprop_buffer.template flat<T>().data();

      for (int64_t b = start; b < limit; ++b) {
        for (int64_t in_r = 0; in_r < args.in_rows; ++in_r) {
          for (int64_t in_c = 0; in_c < args.in_cols; ++in_c) {
            // Populate 'out_bprop_buf' from local 'out_backprop' region.
            CopyOutputBackpropRegion<T>(
                args, padded_filter_inner_dim_size, in_r, in_c,
                out_backprop + b * output_image_size, out_bprop_buf);

            // Compute depthwise backprop input.
            ComputeBackpropInput<T>(args, padded_filter_inner_dim_size, in_r,
                                    in_c, filter_data, out_bprop_buf,
                                    in_bprop_buf,
                                    in_backprop + b * input_image_size);
          }
        }
      }
    };

    const int64_t shard_cost = args.in_rows * args.in_cols * args.out_depth;
    auto worker_threads = *(ctx->device()->tensorflow_cpu_worker_threads());
    Shard(worker_threads.num_threads, worker_threads.workers, args.batch,
          shard_cost, shard);
  }


  explicit DepthwiseConv2dNativeBackpropFilterOp(OpKernelConstruction* context)
      : OpKernel(context) {
    OP_REQUIRES_OK(context, context->GetAttr("strides", &strides_));
    OP_REQUIRES(context, strides_.size() == 4,
                errors::InvalidArgument("Sliding window strides field must "
                                        "specify 4 dimensions"));

    string data_format;
    OP_REQUIRES_OK(context, context->GetAttr("data_format", &data_format));
    OP_REQUIRES(context, FormatFromString(data_format, &data_format_),
                errors::InvalidArgument("Invalid data format"));

    stride_ = GetTensorDim(strides_, data_format_, 'H');
    const int64_t stride_w = GetTensorDim(strides_, data_format_, 'W');
    const int64_t stride_n = GetTensorDim(strides_, data_format_, 'N');
    const int64_t stride_c = GetTensorDim(strides_, data_format_, 'C');

    OP_REQUIRES(context, stride_ == stride_w,
                errors::InvalidArgument(
                    "Current implementation only supports equal length "
                    "strides in the row and column dimensions."));
    OP_REQUIRES(
        context, (stride_n == 1 && stride_c == 1),
        errors::InvalidArgument("Current implementation does not yet support "
                                "strides in the batch and depth dimensions."));
    OP_REQUIRES_OK(context, context->GetAttr("padding", &padding_));
    OP_REQUIRES_OK(context,
                   context->GetAttr("explicit_paddings", &explicit_paddings_));
    OP_REQUIRES_OK(context, CheckValidPadding(padding_, explicit_paddings_,
                                              /*num_dims=*/4, data_format_));

    cudnn_use_autotune_ = CudnnUseAutotune();

    if (std::is_same<T, bfloat16>::value) {
      dtype_ = DT_BFLOAT16;
    } else if (std::is_same<T, Eigen::half>::value) {
      dtype_ = DT_HALF;
    } else if (std::is_same<T, float>::value) {
      dtype_ = DT_FLOAT;
    } else if (std::is_same<T, double>::value) {
      dtype_ = DT_DOUBLE;
    } else {
      LOG(ERROR) << "Only bfloat16, half, float, and double are supported.";
    }
#if CUDNN_VERSION >= 7603
    // Use CuDNN grouped conv (filter gradients) when input/output is
    // float16(half). See cudnn release note 7.6.3. (https://docs.nvidia.com/dee
    // plearning/sdk/cudnn-release-notes/rel_763.html#rel_763)
    //
    // Grouped convolution was added to cuDNN in version 7.0.1 but
    // TensorFlow op-determinism has been added only for cuDNN versions 7.6.3
    // and later intentionally. This is to avoid potential issues with earlier
    // versions of cuDNN.
    use_cudnn_grouped_conv_ = OpDeterminismRequired() || dtype_ == DT_HALF;
#else
    use_cudnn_grouped_conv_ = false;
#endif
  }


int DecodeTeredo(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{
    if (!g_teredo_enabled)
        return TM_ECODE_FAILED;

    uint8_t *start = pkt;

    /* Is this packet to short to contain an IPv6 packet ? */
    if (len < IPV6_HEADER_LEN)
        return TM_ECODE_FAILED;

    /* Teredo encapsulate IPv6 in UDP and can add some custom message
     * part before the IPv6 packet. In our case, we just want to get
     * over an ORIGIN indication. So we just make one offset if needed. */
    if (start[0] == 0x0) {
        switch (start[1]) {
            /* origin indication: compatible with tunnel */
            case 0x0:
                /* offset is coherent with len and presence of an IPv6 header */
                if (len >= TEREDO_ORIG_INDICATION_LENGTH + IPV6_HEADER_LEN)
                    start += TEREDO_ORIG_INDICATION_LENGTH;
                else
                    return TM_ECODE_FAILED;
                break;
            /* authentication: negotiation not real tunnel */
            case 0x1:
                return TM_ECODE_FAILED;
            /* this case is not possible in Teredo: not that protocol */
            default:
                return TM_ECODE_FAILED;
        }
    }

    /* There is no specific field that we can check to prove that the packet
     * is a Teredo packet. We've zapped here all the possible Teredo header
     * and we should have an IPv6 packet at the start pointer.
     * We then can only do a few checks before sending the encapsulated packets
     * to decoding:
     *  - The packet has a protocol version which is IPv6.
     *  - The IPv6 length of the packet matches what remains in buffer.
     *  - HLIM is 0. This would technically be valid, but still weird.
     *  - NH 0 (HOP) and not enough data.
     *
     *  If all these conditions are met, the tunnel decoder will be called.
     *  If the packet gets an invalid event set, it will still be rejected.
     */
    if (IP_GET_RAW_VER(start) == 6) {
        IPV6Hdr *thdr = (IPV6Hdr *)start;

        /* ignore hoplimit 0 packets, most likely an artifact of bad detection */
        if (IPV6_GET_RAW_HLIM(thdr) == 0)
            return TM_ECODE_FAILED;

        /* if nh is 0 (HOP) with little data we have a bogus packet */
        if (IPV6_GET_RAW_NH(thdr) == 0 && IPV6_GET_RAW_PLEN(thdr) < 8)
            return TM_ECODE_FAILED;

        if (len ==  IPV6_HEADER_LEN +
                IPV6_GET_RAW_PLEN(thdr) + (start - pkt)) {
            if (pq != NULL) {
                int blen = len - (start - pkt);
                /* spawn off tunnel packet */
                Packet *tp = PacketTunnelPktSetup(tv, dtv, p, start, blen,
                                                  DECODE_TUNNEL_IPV6_TEREDO, pq);
                if (tp != NULL) {
                    PKT_SET_SRC(tp, PKT_SRC_DECODER_TEREDO);
                    /* add the tp to the packet queue. */
                    PacketEnqueue(pq,tp);
                    StatsIncr(tv, dtv->counter_teredo);
                    return TM_ECODE_OK;
                }
            }
        }
        return TM_ECODE_FAILED;
    }

    return TM_ECODE_FAILED;
}


void DecodeTeredoConfig(void)
{
    int enabled = 0;
    if (ConfGetBool("decoder.teredo.enabled", &enabled) == 1) {
        if (enabled) {
            g_teredo_enabled = true;
        } else {
            g_teredo_enabled = false;
        }
    }
}


int DecodeIPV6(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p, uint8_t *pkt, uint16_t len, PacketQueue *pq)
{
    int ret;

    StatsIncr(tv, dtv->counter_ipv6);

    /* do the actual decoding */
    ret = DecodeIPV6Packet (tv, dtv, p, pkt, len);
    if (unlikely(ret < 0)) {
        p->ip6h = NULL;
        return TM_ECODE_FAILED;
    }

#ifdef DEBUG
    if (SCLogDebugEnabled()) { /* only convert the addresses if debug is really enabled */
        /* debug print */
        char s[46], d[46];
        PrintInet(AF_INET6, (const void *)GET_IPV6_SRC_ADDR(p), s, sizeof(s));
        PrintInet(AF_INET6, (const void *)GET_IPV6_DST_ADDR(p), d, sizeof(d));
        SCLogDebug("IPV6 %s->%s - CLASS: %" PRIu32 " FLOW: %" PRIu32 " NH: %" PRIu32 " PLEN: %" PRIu32 " HLIM: %" PRIu32 "", s,d,
                IPV6_GET_CLASS(p), IPV6_GET_FLOW(p), IPV6_GET_NH(p), IPV6_GET_PLEN(p),
                IPV6_GET_HLIM(p));
    }
#endif /* DEBUG */

    /* now process the Ext headers and/or the L4 Layer */
    switch(IPV6_GET_NH(p)) {
        case IPPROTO_TCP:
            IPV6_SET_L4PROTO (p, IPPROTO_TCP);
            DecodeTCP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_UDP:
            IPV6_SET_L4PROTO (p, IPPROTO_UDP);
            DecodeUDP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_ICMPV6:
            IPV6_SET_L4PROTO (p, IPPROTO_ICMPV6);
            DecodeICMPV6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_SCTP:
            IPV6_SET_L4PROTO (p, IPPROTO_SCTP);
            DecodeSCTP(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_IPIP:
            IPV6_SET_L4PROTO(p, IPPROTO_IPIP);
            DecodeIPv4inIPv6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_IPV6:
            DecodeIP6inIP6(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            return TM_ECODE_OK;
        case IPPROTO_FRAGMENT:
        case IPPROTO_HOPOPTS:
        case IPPROTO_ROUTING:
        case IPPROTO_NONE:
        case IPPROTO_DSTOPTS:
        case IPPROTO_AH:
        case IPPROTO_ESP:
        case IPPROTO_MH:
        case IPPROTO_HIP:
        case IPPROTO_SHIM6:
            DecodeIPV6ExtHdrs(tv, dtv, p, pkt + IPV6_HEADER_LEN, IPV6_GET_PLEN(p), pq);
            break;
        case IPPROTO_ICMP:
            ENGINE_SET_EVENT(p,IPV6_WITH_ICMPV4);
            break;
        default:
            ENGINE_SET_EVENT(p, IPV6_UNKNOWN_NEXT_HEADER);
            IPV6_SET_L4PROTO (p, IPV6_GET_NH(p));
            break;
    }
    p->proto = IPV6_GET_L4PROTO (p);

    /* Pass to defragger if a fragment. */
    if (IPV6_EXTHDR_ISSET_FH(p)) {
        Packet *rp = Defrag(tv, dtv, p, pq);
        if (rp != NULL) {
            PacketEnqueue(pq,rp);
        }
    }

    return TM_ECODE_OK;
}


Packet *PacketGetFromQueueOrAlloc(void)
{
    /* try the pool first */
    Packet *p = PacketPoolGetPacket();

    if (p == NULL) {
        /* non fatal, we're just not processing a packet then */
        p = PacketGetFromAlloc();
    } else {
        PACKET_PROFILING_START(p);
    }

    return p;
}