static uint8_t cirrus_mmio_blt_read(CirrusVGAState * s, unsigned address)
{
    int value = 0xff;

    switch (address) {
    case (CIRRUS_MMIO_BLTBGCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x00);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x10);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 2):
	value = cirrus_vga_read_gr(s, 0x12);
	break;
    case (CIRRUS_MMIO_BLTBGCOLOR + 3):
	value = cirrus_vga_read_gr(s, 0x14);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x01);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x11);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 2):
	value = cirrus_vga_read_gr(s, 0x13);
	break;
    case (CIRRUS_MMIO_BLTFGCOLOR + 3):
	value = cirrus_vga_read_gr(s, 0x15);
	break;
    case (CIRRUS_MMIO_BLTWIDTH + 0):
	value = cirrus_vga_read_gr(s, 0x20);
	break;
    case (CIRRUS_MMIO_BLTWIDTH + 1):
	value = cirrus_vga_read_gr(s, 0x21);
	break;
    case (CIRRUS_MMIO_BLTHEIGHT + 0):
	value = cirrus_vga_read_gr(s, 0x22);
	break;
    case (CIRRUS_MMIO_BLTHEIGHT + 1):
	value = cirrus_vga_read_gr(s, 0x23);
	break;
    case (CIRRUS_MMIO_BLTDESTPITCH + 0):
	value = cirrus_vga_read_gr(s, 0x24);
	break;
    case (CIRRUS_MMIO_BLTDESTPITCH + 1):
	value = cirrus_vga_read_gr(s, 0x25);
	break;
    case (CIRRUS_MMIO_BLTSRCPITCH + 0):
	value = cirrus_vga_read_gr(s, 0x26);
	break;
    case (CIRRUS_MMIO_BLTSRCPITCH + 1):
	value = cirrus_vga_read_gr(s, 0x27);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 0):
	value = cirrus_vga_read_gr(s, 0x28);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 1):
	value = cirrus_vga_read_gr(s, 0x29);
	break;
    case (CIRRUS_MMIO_BLTDESTADDR + 2):
	value = cirrus_vga_read_gr(s, 0x2a);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 0):
	value = cirrus_vga_read_gr(s, 0x2c);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 1):
	value = cirrus_vga_read_gr(s, 0x2d);
	break;
    case (CIRRUS_MMIO_BLTSRCADDR + 2):
	value = cirrus_vga_read_gr(s, 0x2e);
	break;
    case CIRRUS_MMIO_BLTWRITEMASK:
	value = cirrus_vga_read_gr(s, 0x2f);
	break;
    case CIRRUS_MMIO_BLTMODE:
	value = cirrus_vga_read_gr(s, 0x30);
	break;
    case CIRRUS_MMIO_BLTROP:
	value = cirrus_vga_read_gr(s, 0x32);
	break;
    case CIRRUS_MMIO_BLTMODEEXT:
	value = cirrus_vga_read_gr(s, 0x33);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 0):
	value = cirrus_vga_read_gr(s, 0x34);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLOR + 1):
	value = cirrus_vga_read_gr(s, 0x35);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 0):
	value = cirrus_vga_read_gr(s, 0x38);
	break;
    case (CIRRUS_MMIO_BLTTRANSPARENTCOLORMASK + 1):
	value = cirrus_vga_read_gr(s, 0x39);
	break;
    case CIRRUS_MMIO_BLTSTATUS:
	value = cirrus_vga_read_gr(s, 0x31);
	break;
    default:
#ifdef DEBUG_CIRRUS
	printf("cirrus: mmio read - address 0x%04x\n", address);
#endif
	break;
    }

    return (uint8_t) value;
}


static void cirrus_invalidate_region(CirrusVGAState * s, int off_begin,
				     int off_pitch, int bytesperline,
				     int lines)
{
    int y;
    int off_cur;
    int off_cur_end;

    if (off_pitch < 0) {
        off_begin -= bytesperline - 1;
    }

    for (y = 0; y < lines; y++) {
	off_cur = off_begin;
	off_cur_end = (off_cur + bytesperline) & s->cirrus_addr_mask;
        assert(off_cur_end >= off_cur);
        memory_region_set_dirty(&s->vga.vram, off_cur, off_cur_end - off_cur);
	off_begin += off_pitch;
    }
}


read_unknown_extension(Gif_Context* gfc, Gif_Reader* grr,
                       int kind, char* appname, int applength)
{
    uint8_t block_len = gifgetbyte(grr);
    uint8_t* data = 0;
    int data_len = 0;
    Gif_Extension *gfex = 0;

    while (block_len > 0) {
        Gif_ReArray(data, uint8_t, data_len + block_len + 2);
        if (!data)
            goto done;
        data[data_len] = block_len;
        gifgetblock(data + data_len + 1, block_len, grr);
        data_len += block_len + 1;
        block_len = gifgetbyte(grr);
    }

    if (data)
        gfex = Gif_NewExtension(kind, appname, applength);
    if (gfex) {
        gfex->data = data;
        gfex->free_data = Gif_Free;
        gfex->length = data_len;
        gfex->packetized = 1;
        data[data_len] = 0;
        Gif_AddExtension(gfc->stream, gfc->gfi, gfex);
    }

 done:
    if (!gfex)
        Gif_DeleteArray(data);
    while (block_len > 0) {
        uint8_t buffer[GIF_MAX_BLOCK];
        gifgetblock(buffer, block_len, grr);
        block_len = gifgetbyte(grr);
    }
    return gfex != 0;
}


read_image_block(Gif_Reader *grr, uint8_t *buffer, int *bit_pos_store,
		 int *bit_len_store, int bits_needed)
{
  int bit_position = *bit_pos_store;
  int bit_length = *bit_len_store;
  uint8_t block_len;

  while (bit_position + bits_needed > bit_length) {
    /* Read in the next data block. */
    if (bit_position >= 8) {
      /* Need to shift down the upper, unused part of 'buffer' */
      int i = bit_position / 8;
      buffer[0] = buffer[i];
      buffer[1] = buffer[i+1];
      bit_position -= i * 8;
      bit_length -= i * 8;
    }
    block_len = gifgetbyte(grr);
    GIF_DEBUG(("\nimage_block(%d) ", block_len));
    if (block_len == 0) return 0;
    gifgetblock(buffer + bit_length / 8, block_len, grr);
    bit_length += block_len * 8;
  }

  *bit_pos_store = bit_position;
  *bit_len_store = bit_length;
  return 1;
}


read_image_data(Gif_Context *gfc, Gif_Reader *grr)
{
  /* we need a bit more than GIF_MAX_BLOCK in case a single code is split
     across blocks */
  uint8_t buffer[GIF_MAX_BLOCK + 5];
  int i;
  uint32_t accum;

  int bit_position;
  int bit_length;

  Gif_Code code;
  Gif_Code old_code;
  Gif_Code clear_code;
  Gif_Code eoi_code;
  Gif_Code next_code;
#define CUR_BUMP_CODE (1 << bits_needed)
#define CUR_CODE_MASK ((1 << bits_needed) - 1)

  int min_code_size;
  int bits_needed;

  gfc->decodepos = 0;

  min_code_size = gifgetbyte(grr);
  GIF_DEBUG(("\n\nmin_code_size(%d) ", min_code_size));
  if (min_code_size >= GIF_MAX_CODE_BITS) {
    gif_read_error(gfc, 1, "image corrupted, min_code_size too big");
    min_code_size = GIF_MAX_CODE_BITS - 1;
  } else if (min_code_size < 2) {
    gif_read_error(gfc, 1, "image corrupted, min_code_size too small");
    min_code_size = 2;
  }
  clear_code = 1 << min_code_size;
  for (code = 0; code < clear_code; code++) {
    gfc->prefix[code] = 49428;
    gfc->suffix[code] = (uint8_t)code;
    gfc->length[code] = 1;
  }
  eoi_code = clear_code + 1;

  next_code = eoi_code;
  bits_needed = min_code_size + 1;

  code = clear_code;

  bit_length = bit_position = 0;
  /* Thus the 'Read in the next data block.' code below will be invoked on the
     first time through: exactly right! */

  while (1) {

    old_code = code;

    /* GET A CODE INTO THE 'code' VARIABLE.
     *
     * 9.Dec.1998 - Rather than maintain a byte pointer and a bit offset into
     * the current byte (and the processing associated with that), we maintain
     * one number: the offset, in bits, from the beginning of 'buffer'. This
     * much cleaner choice was inspired by Patrick J. Naughton
     * <naughton@wind.sun.com>'s GIF-reading code, which does the same thing.
     * His code distributed as part of XV in xvgif.c. */

    if (bit_position + bits_needed > bit_length)
      /* Read in the next data block. */
      if (!read_image_block(grr, buffer, &bit_position, &bit_length,
			    bits_needed))
	goto zero_length_block;

    i = bit_position / 8;
    accum = buffer[i] + (buffer[i+1] << 8);
    if (bits_needed >= 8)
      accum |= (buffer[i+2]) << 16;
    code = (Gif_Code)((accum >> (bit_position % 8)) & CUR_CODE_MASK);
    bit_position += bits_needed;

    GIF_DEBUG(("%d ", code));

    /* CHECK FOR SPECIAL OR BAD CODES: clear_code, eoi_code, or a code that is
     * too large. */
    if (code == clear_code) {
      GIF_DEBUG(("clear "));
      bits_needed = min_code_size + 1;
      next_code = eoi_code;
      continue;

    } else if (code == eoi_code)
      break;

    else if (code > next_code && next_code && next_code != clear_code) {
      /* code > next_code: a (hopefully recoverable) error.

	 Bug fix, 5/27: Do this even if old_code == clear_code, and set code
	 to 0 to prevent errors later. (If we didn't zero code, we'd later set
	 old_code = code; then we had old_code >= next_code; so the prefixes
	 array got all screwed up!)

	 Bug fix, 4/12/2010: It is not an error if next_code == clear_code.
	 This happens at the end of a large GIF: see the next comment ("If no
	 meaningful next code should be defined...."). */
      if (gfc->errors[1] < 20)
          gif_read_error(gfc, 1, "image corrupted, code out of range");
      else if (gfc->errors[1] == 20)
          gif_read_error(gfc, 1, "(not reporting more errors)");
      code = 0;
    }

    /* PROCESS THE CURRENT CODE and define the next code. If no meaningful
     * next code should be defined, then we have set next_code to either
     * 'eoi_code' or 'clear_code' -- so we'll store useless prefix/suffix data
     * in a useless place. */

    /* *First,* set up the prefix and length for the next code
       (in case code == next_code). */
    gfc->prefix[next_code] = old_code;
    gfc->length[next_code] = gfc->length[old_code] + 1;

    /* Use one_code to process code. It's nice that it returns the first
       pixel in code: that's what we need. */
    gfc->suffix[next_code] = one_code(gfc, code);

    /* Special processing if code == next_code: we didn't know code's final
       suffix when we called one_code, but we do now. */
    /* 7.Mar.2014 -- Avoid error if image has zero width/height. */
    if (code == next_code && gfc->image + gfc->decodepos <= gfc->maximage)
      gfc->image[gfc->decodepos - 1] = gfc->suffix[next_code];

    /* Increment next_code except for the 'clear_code' special case (that's
       when we're reading at the end of a GIF) */
    if (next_code != clear_code) {
      next_code++;
      if (next_code == CUR_BUMP_CODE) {
	if (bits_needed < GIF_MAX_CODE_BITS)
	  bits_needed++;
	else
	  next_code = clear_code;
      }
    }

  }

  /* read blocks until zero-length reached. */
  i = gifgetbyte(grr);
  GIF_DEBUG(("\nafter_image(%d)\n", i));
  while (i > 0) {
    gifgetblock(buffer, i, grr);
    i = gifgetbyte(grr);
    GIF_DEBUG(("\nafter_image(%d)\n", i));
  }

  /* zero-length block reached. */
 zero_length_block: {
      long delta = (long) (gfc->maximage - gfc->image) - (long) gfc->decodepos;
      char buf[BUFSIZ];
      if (delta > 0) {
          sprintf(buf, "missing %ld %s of image data", delta,
                  delta == 1 ? "pixel" : "pixels");
          gif_read_error(gfc, 1, buf);
          memset(&gfc->image[gfc->decodepos], 0, delta);
      } else if (delta < -1) {
          /* One pixel of superfluous data is OK; that could be the
             code == next_code case. */
          sprintf(buf, "%ld superfluous pixels of image data", -delta);
          gif_read_error(gfc, 0, buf);
      }
  }
}


void ContentLine_Analyzer::SkipBytesAfterThisLine(int64_t length)
	{
	// This is a little complicated because Bro has to handle
	// both CR and CRLF as a line break. When a line is delivered,
	// it's possible that only a CR is seen, and we may not know
	// if an LF is following until we see the next packet.  If an
	// LF follows, we should start skipping bytes *after* the LF.
	// So we keep the skip as 'pending' until we see the next
	// character in DoDeliver().

	if ( last_char == '\r' )
		skip_pending = length;
	else
		SkipBytes(length);
	}


void ContentLine_Analyzer::SetPlainDelivery(int64_t length)
	{
	if ( length < 0 )
		{
		reporter->AnalyzerError(this,
		                                "negative length for plain delivery");
		return;
		}

	plain_delivery_length = length;
	}


static int rtnl_net_dumpid_one(int id, void *peer, void *data)
{
	struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data;
	int ret;

	if (net_cb->idx < net_cb->s_idx)
		goto cont;

	ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid,
			    net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI,
			    RTM_NEWNSID, net_cb->net, id);
	if (ret < 0)
		return ret;

cont:
	net_cb->idx++;
	return 0;
}


static void unregister_pernet_operations(struct pernet_operations *ops)
{

	__unregister_pernet_operations(ops);
	rcu_barrier();
	if (ops->id)
		ida_remove(&net_generic_ids, *ops->id);
}


static int register_pernet_operations(struct list_head *list,
				      struct pernet_operations *ops)
{
	int error;

	if (ops->id) {
again:
		error = ida_get_new_above(&net_generic_ids, MIN_PERNET_OPS_ID, ops->id);
		if (error < 0) {
			if (error == -EAGAIN) {
				ida_pre_get(&net_generic_ids, GFP_KERNEL);
				goto again;
			}
			return error;
		}
		max_gen_ptrs = max(max_gen_ptrs, *ops->id + 1);
	}
	error = __register_pernet_operations(list, ops);
	if (error) {
		rcu_barrier();
		if (ops->id)
			ida_remove(&net_generic_ids, *ops->id);
	}

	return error;
}


static void ops_exit_list(const struct pernet_operations *ops,
			  struct list_head *net_exit_list)
{
	struct net *net;
	if (ops->exit) {
		list_for_each_entry(net, net_exit_list, exit_list)
			ops->exit(net);
	}
	if (ops->exit_batch)
		ops->exit_batch(net_exit_list);
}


static int ops_init(const struct pernet_operations *ops, struct net *net)
{
	int err = -ENOMEM;
	void *data = NULL;

	if (ops->id && ops->size) {
		data = kzalloc(ops->size, GFP_KERNEL);
		if (!data)
			goto out;

		err = net_assign_generic(net, *ops->id, data);
		if (err)
			goto cleanup;
	}
	err = 0;
	if (ops->init)
		err = ops->init(net);
	if (!err)
		return 0;

cleanup:
	kfree(data);

out:
	return err;
}


static int __peernet2id(struct net *net, struct net *peer)
{
	bool no = false;

	return __peernet2id_alloc(net, peer, &no);
}


static int __net_init net_defaults_init_net(struct net *net)
{
	net->core.sysctl_somaxconn = SOMAXCONN;
	return 0;
}


ZipStreamBuf::ZipStreamBuf(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool reposition):
	Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out),
	_pIstr(0),
	_pOstr(&ostr),
	_ptrBuf(),
	_ptrOBuf(),
	_ptrHelper(),
	_ptrOHelper(),
	_crc32(Poco::Checksum::TYPE_CRC32),
	_expectedCrc32(0),
	_checkCRC(false),
	_bytesWritten(0),
	_pHeader(&fileEntry)
{
	if (fileEntry.isEncrypted())
		throw Poco::NotImplementedException("Encryption not supported");

	if (fileEntry.isDirectory())
	{
		// only header, no payload, zero crc
		fileEntry.setSearchCRCAndSizesAfterData(false);
		fileEntry.setCompressedSize(0);
		fileEntry.setUncompressedSize(0);
		fileEntry.setCRC(0);
		std::string header = fileEntry.createHeader();
		ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
	}
	else
	{
		fileEntry.setSearchCRCAndSizesAfterData(!reposition);
		if (fileEntry.getCompressionMethod() == ZipCommon::CM_DEFLATE)
		{
			int level = Z_DEFAULT_COMPRESSION;
			if (fileEntry.getCompressionLevel() == ZipCommon::CL_FAST || fileEntry.getCompressionLevel() == ZipCommon::CL_SUPERFAST)
				level = Z_BEST_SPEED;
			else if (fileEntry.getCompressionLevel() == ZipCommon::CL_MAXIMUM)
				level = Z_BEST_COMPRESSION;
			// ignore the zlib init string which is of size 2 and also ignore the 4 byte adler32 value at the end of the stream!
			_ptrOHelper = new PartialOutputStream(*_pOstr, 2, 4, false);
			_ptrOBuf = new Poco::DeflatingOutputStream(*_ptrOHelper, DeflatingStreamBuf::STREAM_ZLIB, level);
		}
		else if (fileEntry.getCompressionMethod() == ZipCommon::CM_STORE)
		{
			_ptrOHelper = new PartialOutputStream(*_pOstr, 0, 0, false);
			_ptrOBuf = new PartialOutputStream(*_ptrOHelper, 0, 0, false);
		}
		else throw Poco::NotImplementedException("Unsupported compression method");

		// now write the header to the ostr!
        if (fileEntry.needsZip64())
            fileEntry.setZip64Data();
		std::string header = fileEntry.createHeader();
		ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
	}
}


bool Decompress::handleZipEntry(std::istream& zipStream, const ZipLocalFileHeader& hdr)
{
	if (hdr.isDirectory())
	{
		// directory have 0 size, nth to read
		if (!_flattenDirs)
		{
			std::string dirName = hdr.getFileName();
			if (!ZipCommon::isValidPath(dirName))
				throw ZipException("Illegal entry name", dirName);
			Poco::Path dir(_outDir, dirName);
			dir.makeDirectory();
			Poco::File aFile(dir);
			aFile.createDirectories();
		}
		return true;
	}
	try
	{
		std::string fileName = hdr.getFileName();
		if (_flattenDirs)
		{
			// remove path info
			Poco::Path p(fileName);
			p.makeFile();
			fileName = p.getFileName();
		}

		if (!ZipCommon::isValidPath(fileName))
			throw ZipException("Illegal entry name", fileName);

		Poco::Path file(fileName);
		file.makeFile();
		Poco::Path dest(_outDir, file);
		dest.makeFile();
		if (dest.depth() > 0)
		{
			Poco::File aFile(dest.parent());
			aFile.createDirectories();
		}
		Poco::FileOutputStream out(dest.toString());
		ZipInputStream inp(zipStream, hdr, false);
		Poco::StreamCopier::copyStream(inp, out);
		out.close();
		Poco::File aFile(dest.toString());
		if (!aFile.exists() || !aFile.isFile())
		{
			std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Failed to create output stream " + dest.toString());
			EError.notify(this, tmp);
			return false;
		}

		if (!inp.crcValid())
		{
			if (!_keepIncompleteFiles)
				aFile.remove();
			std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "CRC mismatch. Corrupt file: " + dest.toString());
			EError.notify(this, tmp);
			return false;
		}

		// cannot check against hdr.getUnCompressedSize if CRC and size are not set in hdr but in a ZipDataInfo
		// crc is typically enough to detect errors
		if (aFile.getSize() != hdr.getUncompressedSize() && !hdr.searchCRCAndSizesAfterData())
		{
			if (!_keepIncompleteFiles)
				aFile.remove();
			std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Filesizes do not match. Corrupt file: " + dest.toString());
			EError.notify(this, tmp);
			return false;
		}

		std::pair<const ZipLocalFileHeader, const Poco::Path> tmp = std::make_pair(hdr, file);
		EOk.notify(this, tmp);
	}
	catch (Poco::Exception& e)
	{
		std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Exception: " + e.displayText()));
		EError.notify(this, tmp);
		return false;
	}
	catch (...)
	{
		std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Unknown Exception"));
		EError.notify(this, tmp);
		return false;
	}

	return true;
}


CompressTest::CompressTest(const std::string& name): CppUnit::TestCase(name)
{
}


void CompressTest::createDataFile(const std::string& path, Poco::UInt64 size)
{
	std::ofstream out(path.c_str(), std::ios::binary | std::ios::trunc);
	assert( ! out.fail() );
	Poco::Buffer<char> buffer(MB);
	for(int i = 0; size != 0; i++) {
		std::memset(buffer.begin(), i, buffer.size());
		Poco::UInt64 bytesToWrite = std::min(size, static_cast<Poco::UInt64>(buffer.size()));
		out.write(buffer.begin(), bytesToWrite);
		assert( ! out.fail() );
		size -= bytesToWrite;
	}
	out.flush();
	assert( ! out.fail() );
	out.close();
	assert( ! out.fail() );
}


void CompressTest::testSingleFile()
{
	std::ofstream out(Poco::Path::temp() + "appinf.zip", std::ios::binary);
	Poco::Path theFile(ZipTest::getTestFile("data", "test.zip"));
	Compress c(out, true);
	c.addFile(theFile, theFile.getFileName());
	ZipArchive a(c.close());
}


void ZipTest::testValidPath()
{
	assert (ZipCommon::isValidPath("."));
	assert (ZipCommon::isValidPath("file.txt"));
	assert (ZipCommon::isValidPath(".file.txt"));
	assert (ZipCommon::isValidPath("..file.txt"));
	assert (ZipCommon::isValidPath("file.txt.."));
	assert (ZipCommon::isValidPath(".file..txt"));
	assert (ZipCommon::isValidPath("~file..txt"));
	assert (ZipCommon::isValidPath("~file/~"));
	assert (ZipCommon::isValidPath("dir/~"));
	assert (ZipCommon::isValidPath("some"));
	assert (ZipCommon::isValidPath("some/dir"));
	assert (ZipCommon::isValidPath("some/dir/or/another"));
	assert (ZipCommon::isValidPath("some/dir/./another"));
	assert (ZipCommon::isValidPath("some/dir/or/another/file.txt"));
	assert (ZipCommon::isValidPath("s~me\\d.r\\.or..\\an..her\\file.txt"));
	assert (ZipCommon::isValidPath("some\\dir\\or\\another"));
	assert (ZipCommon::isValidPath("some\\dir\\or\\another\\file.txt"));
	assert (ZipCommon::isValidPath("s~me\\d.r/.or..\\an..her\\file.txt"));

	assert (!ZipCommon::isValidPath("/../"));
	assert (!ZipCommon::isValidPath("/"));
	assert (!ZipCommon::isValidPath("\\..\\"));
	assert (!ZipCommon::isValidPath("/..\\"));
	assert (!ZipCommon::isValidPath("\\../"));
	assert (!ZipCommon::isValidPath(".."));
	assert (!ZipCommon::isValidPath("~/"));
	assert (!ZipCommon::isValidPath("~/~"));
	assert (!ZipCommon::isValidPath("/~"));
	assert (!ZipCommon::isValidPath("/file.txt"));
	assert (!ZipCommon::isValidPath("~/file.txt"));
	assert (!ZipCommon::isValidPath("some/dir/or/../another/file.txt"));
	assert (!ZipCommon::isValidPath("C:\\Windows\\system32"));
}


bool ZipInputStream::crcValid() const
{
	return _buf.crcValid();
}


bool ZipCommon::isValidPath(const std::string& path)
{
	try
	{
		if (Path(path, Path::PATH_UNIX).isAbsolute() || Path(path, Path::PATH_WINDOWS).isAbsolute())
			return false;
	}
	catch (...)
	{
		return false;
	}

	if (path == "..")
		return false;
	if ((path.size() >= 3) && path.compare(0, 3, "../") == 0)
		return false;
	if ((path.size() >= 3) && path.compare(0, 3, "..\\") == 0)
		return false;
	if (path.find("/../") != std::string::npos)
		return false;
	if (path.find("\\..\\") != std::string::npos)
		return false;
	if (path.find("/..\\") != std::string::npos)
		return false;
	if (path.find("\\../") != std::string::npos)
		return false;
	if ((path.size() >= 2) && path.compare(0, 2, "~/") == 0)
		return false;

	return true;
}


ZipOutputStream::ZipOutputStream(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool seekableOutput): ZipIOS(ostr, fileEntry, seekableOutput), std::ostream(&_buf)
{
}


ZipInputStream::ZipInputStream(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition): ZipIOS(istr, fileEntry, reposition), std::istream(&_buf)
{
}


static int WM_GetOutput_Gauss(midi * handle, int8_t *buffer, uint32_t size) {
    uint32_t buffer_used = 0;
    uint32_t i;
    struct _mdi *mdi = (struct _mdi *) handle;
    uint32_t real_samples_to_mix = 0;
    uint32_t data_pos;
    int32_t premix, left_mix, right_mix;
    struct _note *note_data = NULL;
    uint32_t count;
    int16_t *sptr;
    double y, xd;
    double *gptr, *gend;
    int left, right, temp_n;
    int ii, jj;
    struct _event *event = mdi->current_event;
    int32_t *tmp_buffer;
    int32_t *out_buffer;

    _WM_Lock(&mdi->lock);

    buffer_used = 0;
    memset(buffer, 0, size);

    if ( (size / 2) > mdi->mix_buffer_size) {
        if ( (size / 2) <= ( mdi->mix_buffer_size * 2 )) {
            mdi->mix_buffer_size += MEM_CHUNK;
        } else {
            mdi->mix_buffer_size = size / 2;
        }
        mdi->mix_buffer = realloc(mdi->mix_buffer, mdi->mix_buffer_size * sizeof(int32_t));
    }

    tmp_buffer = mdi->mix_buffer;

    memset(tmp_buffer, 0, ((size / 2) * sizeof(int32_t)));
    out_buffer = tmp_buffer;

    do {
        if (__builtin_expect((!mdi->samples_to_mix), 0)) {
            while ((!mdi->samples_to_mix) && (event->do_event)) {
                event->do_event(mdi, &event->event_data);
                if ((mdi->extra_info.mixer_options & WM_MO_LOOP) && (event[0].do_event == *_WM_do_meta_endoftrack)) {
                    _WM_ResetToStart(mdi);
                    event = mdi->current_event;
                } else {
                    mdi->samples_to_mix = event->samples_to_next;
                    event++;
                    mdi->current_event = event;
                }
            }

            if (!mdi->samples_to_mix) {
                if (mdi->extra_info.current_sample
                    >= mdi->extra_info.approx_total_samples) {
                    break;
                } else if ((mdi->extra_info.approx_total_samples
                            - mdi->extra_info.current_sample) > (size >> 2)) {
                    mdi->samples_to_mix = size >> 2;
                } else {
                    mdi->samples_to_mix = mdi->extra_info.approx_total_samples
                    - mdi->extra_info.current_sample;
                }
            }
        }
        if (__builtin_expect((mdi->samples_to_mix > (size >> 2)), 1)) {
            real_samples_to_mix = size >> 2;
        } else {
            real_samples_to_mix = mdi->samples_to_mix;
            if (real_samples_to_mix == 0) {
                continue;
            }
        }

        /* do mixing here */
        count = real_samples_to_mix;
        do {
            note_data = mdi->note;
            left_mix = right_mix = 0;
            if (__builtin_expect((note_data != NULL), 1)) {
                while (note_data) {
                    /*
                     * ===================
                     * resample the sample
                     * ===================
                     */
                    data_pos = note_data->sample_pos >> FPBITS;

                    /* check to see if we're near one of the ends */
                    left = data_pos;
                    right = (note_data->sample->data_length >> FPBITS) - left
                            - 1;
                    temp_n = (right << 1) - 1;
                    if (temp_n <= 0)
                        temp_n = 1;
                    if (temp_n > (left << 1) + 1)
                        temp_n = (left << 1) + 1;

                    /* use Newton if we can't fill the window */
                    if (temp_n < gauss_n) {
                        xd = note_data->sample_pos & FPMASK;
                        xd /= (1L << FPBITS);
                        xd += temp_n >> 1;
                        y = 0;
                        sptr = note_data->sample->data
                                + (note_data->sample_pos >> FPBITS)
                                - (temp_n >> 1);
                        for (ii = temp_n; ii;) {
                            for (jj = 0; jj <= ii; jj++)
                                y += sptr[jj] * newt_coeffs[ii][jj];
                            y *= xd - --ii;
                        }
                        y += *sptr;
                    } else { /* otherwise, use Gauss as usual */
                        y = 0;
                        gptr = &gauss_table[(note_data->sample_pos & FPMASK) *
                                     (gauss_n + 1)];
                        gend = gptr + gauss_n;
                        sptr = note_data->sample->data
                                + (note_data->sample_pos >> FPBITS)
                                - (gauss_n >> 1);
                        do {
                            y += *(sptr++) * *(gptr++);
                        } while (gptr <= gend);
                    }

                    premix = (int32_t)((y * (note_data->env_level >> 12)) / 1024);

                    left_mix += (premix * (int32_t)note_data->left_mix_volume) / 1024;
                    right_mix += (premix * (int32_t)note_data->right_mix_volume) / 1024;

                    /*
                     * ========================
                     * sample position checking
                     * ========================
                     */
                    note_data->sample_pos += note_data->sample_inc;
                    if (__builtin_expect(
                                         (note_data->sample_pos > note_data->sample->loop_end),
                                         0)) {
                        if (note_data->modes & SAMPLE_LOOP) {
                            note_data->sample_pos =
                            note_data->sample->loop_start
                            + ((note_data->sample_pos
                                - note_data->sample->loop_start)
                               % note_data->sample->loop_size);
                        } else if (__builtin_expect(
                                                    (note_data->sample_pos
                                                     >= note_data->sample->data_length),
                                                    0)) {
                            goto _END_THIS_NOTE;
                        }
                    }

                    if (__builtin_expect((note_data->env_inc == 0), 0)) {
                        /*
                         fprintf(stderr,"\r\nINC = 0, ENV %i, LEVEL %i, TARGET %d, RATE %i\r\n",
                                 note_data->env, note_data->env_level,
                                 note_data->sample->env_target[note_data->env],
                                 note_data->sample->env_rate[note_data->env]);
                         */
                        note_data = note_data->next;
                        continue;
                    }

                    note_data->env_level += note_data->env_inc;
                    /*
                     fprintf(stderr,"\r\nENV %i, LEVEL %i, TARGET %d, RATE %i, INC %i\r\n",
                             note_data->env, note_data->env_level,
                             note_data->sample->env_target[note_data->env],
                             note_data->sample->env_rate[note_data->env],
                             note_data->env_inc);
                     */
                    if (note_data->env_inc < 0) {
                        if (note_data->env_level
                            > note_data->sample->env_target[note_data->env]) {
                            note_data = note_data->next;
                            continue;
                        }
                    } else if (note_data->env_inc > 0) {
                        if (note_data->env_level
                            < note_data->sample->env_target[note_data->env]) {
                            note_data = note_data->next;
                            continue;
                        }
                    }

                    // Yes could have a condition here but
                    // it would crete another bottleneck

                    note_data->env_level =
                    note_data->sample->env_target[note_data->env];
                    switch (note_data->env) {
                        case 0:
                            if (!(note_data->modes & SAMPLE_ENVELOPE)) {
                                note_data->env_inc = 0;
                                note_data = note_data->next;
                                continue;
                            }
                            break;
                        case 2:
                            if (note_data->modes & SAMPLE_SUSTAIN /*|| note_data->hold*/) {
                                note_data->env_inc = 0;
                                note_data = note_data->next;
                                continue;
                            } else if (note_data->modes & SAMPLE_CLAMPED) {
                                note_data->env = 5;
                                if (note_data->env_level
                                    > note_data->sample->env_target[5]) {
                                    note_data->env_inc =
                                    -note_data->sample->env_rate[5];
                                } else {
                                    note_data->env_inc =
                                    note_data->sample->env_rate[5];
                                }
                                continue;
                            }
                            break;
                        case 5:
                            if (__builtin_expect((note_data->env_level == 0), 1)) {
                                goto _END_THIS_NOTE;
                            }
                            /* sample release */
                            if (note_data->modes & SAMPLE_LOOP)
                                note_data->modes ^= SAMPLE_LOOP;
                            note_data->env_inc = 0;
                            note_data = note_data->next;
                            continue;
                        case 6:
                        _END_THIS_NOTE:
                            if (__builtin_expect((note_data->replay != NULL), 1)) {
                                note_data->active = 0;
                                {
                                    struct _note *prev_note = NULL;
                                    struct _note *nte_array = mdi->note;

                                    if (nte_array != note_data) {
                                        do {
                                            prev_note = nte_array;
                                            nte_array = nte_array->next;
                                        } while (nte_array != note_data);
                                    }
                                    if (prev_note) {
                                        prev_note->next = note_data->replay;
                                    } else {
                                        mdi->note = note_data->replay;
                                    }
                                    note_data->replay->next = note_data->next;
                                    note_data = note_data->replay;
                                    note_data->active = 1;
                                }
                            } else {
                                note_data->active = 0;
                                {
                                    struct _note *prev_note = NULL;
                                    struct _note *nte_array = mdi->note;

                                    if (nte_array != note_data) {
                                        do {
                                            prev_note = nte_array;
                                            nte_array = nte_array->next;
                                        } while ((nte_array != note_data)
                                                 && (nte_array));
                                    }
                                    if (prev_note) {
                                        prev_note->next = note_data->next;
                                    } else {
                                        mdi->note = note_data->next;
                                    }
                                    note_data = note_data->next;
                                }
                            }
                            continue;
                    }
                    note_data->env++;

                    if (note_data->is_off == 1) {
                        _WM_do_note_off_extra(note_data);
                    } else {

                        if (note_data->env_level
                            >= note_data->sample->env_target[note_data->env]) {
                            note_data->env_inc =
                            -note_data->sample->env_rate[note_data->env];
                        } else {
                            note_data->env_inc =
                            note_data->sample->env_rate[note_data->env];
                        }
                    }
                    note_data = note_data->next;
                    continue;
                }
            }
            *tmp_buffer++ = left_mix;
            *tmp_buffer++ = right_mix;
        } while (--count);

        buffer_used += real_samples_to_mix * 4;
        size -= (real_samples_to_mix << 2);
        mdi->extra_info.current_sample += real_samples_to_mix;
        mdi->samples_to_mix -= real_samples_to_mix;
    } while (size);

    tmp_buffer = out_buffer;

    if (mdi->extra_info.mixer_options & WM_MO_REVERB) {
        _WM_do_reverb(mdi->reverb, tmp_buffer, (buffer_used / 2));
    }

    // _WM_DynamicVolumeAdjust(mdi, tmp_buffer, (buffer_used/2));

    for (i = 0; i < buffer_used; i += 4) {
        left_mix = *tmp_buffer++;
        right_mix = *tmp_buffer++;

        /*
         * ===================
         * Write to the buffer
         * ===================
         */
#ifdef WORDS_BIGENDIAN
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
#else
        (*buffer++) = left_mix & 0xff;
        (*buffer++) = ((left_mix >> 8) & 0x7f) | ((left_mix >> 24) & 0x80);
        (*buffer++) = right_mix & 0xff;
        (*buffer++) = ((right_mix >> 8) & 0x7f) | ((right_mix >> 24) & 0x80);
#endif
    }
    _WM_Unlock(&mdi->lock);
    return (buffer_used);
}


static int xor_init(struct loop_device *lo, const struct loop_info64 *info)
{
	if (unlikely(info->lo_encrypt_key_size <= 0))
		return -EINVAL;
	return 0;
}


static int lo_compat_ioctl(struct block_device *bdev, fmode_t mode,
			   unsigned int cmd, unsigned long arg)
{
	struct loop_device *lo = bdev->bd_disk->private_data;
	int err;

	switch(cmd) {
	case LOOP_SET_STATUS:
		mutex_lock(&lo->lo_ctl_mutex);
		err = loop_set_status_compat(
			lo, (const struct compat_loop_info __user *) arg);
		mutex_unlock(&lo->lo_ctl_mutex);
		break;
	case LOOP_GET_STATUS:
		mutex_lock(&lo->lo_ctl_mutex);
		err = loop_get_status_compat(
			lo, (struct compat_loop_info __user *) arg);
		mutex_unlock(&lo->lo_ctl_mutex);
		break;
	case LOOP_SET_CAPACITY:
	case LOOP_CLR_FD:
	case LOOP_GET_STATUS64:
	case LOOP_SET_STATUS64:
		arg = (unsigned long) compat_ptr(arg);
	case LOOP_SET_FD:
	case LOOP_CHANGE_FD:
		err = lo_ioctl(bdev, mode, cmd, arg);
		break;
	default:
		err = -ENOIOCTLCMD;
		break;
	}
	return err;
}


static inline int is_loop_device(struct file *file)
{
	struct inode *i = file->f_mapping->host;

	return i && S_ISBLK(i->i_mode) && MAJOR(i->i_rdev) == LOOP_MAJOR;
}


static int transfer_xor(struct loop_device *lo, int cmd,
			struct page *raw_page, unsigned raw_off,
			struct page *loop_page, unsigned loop_off,
			int size, sector_t real_block)
{
	char *raw_buf = kmap_atomic(raw_page) + raw_off;
	char *loop_buf = kmap_atomic(loop_page) + loop_off;
	char *in, *out, *key;
	int i, keysize;

	if (cmd == READ) {
		in = raw_buf;
		out = loop_buf;
	} else {
		in = loop_buf;
		out = raw_buf;
	}

	key = lo->lo_encrypt_key;
	keysize = lo->lo_encrypt_key_size;
	for (i = 0; i < size; i++)
		*out++ = *in++ ^ key[(i & 511) % keysize];

	kunmap_atomic(loop_buf);
	kunmap_atomic(raw_buf);
	cond_resched();
	return 0;
}


loop_get_status_old(struct loop_device *lo, struct loop_info __user *arg) {
	struct loop_info info;
	struct loop_info64 info64;
	int err = 0;

	if (!arg)
		err = -EINVAL;
	if (!err)
		err = loop_get_status(lo, &info64);
	if (!err)
		err = loop_info64_to_old(&info64, &info);
	if (!err && copy_to_user(arg, &info, sizeof(info)))
		err = -EFAULT;

	return err;
}


loop_set_status64(struct loop_device *lo, const struct loop_info64 __user *arg)
{
	struct loop_info64 info64;

	if (copy_from_user(&info64, arg, sizeof (struct loop_info64)))
		return -EFAULT;
	return loop_set_status(lo, &info64);
}


static int unregister_transfer_cb(int id, void *ptr, void *data)
{
	struct loop_device *lo = ptr;
	struct loop_func_table *xfer = data;

	mutex_lock(&lo->lo_ctl_mutex);
	if (lo->lo_encryption == xfer)
		loop_release_xfer(lo);
	mutex_unlock(&lo->lo_ctl_mutex);
	return 0;
}


static void automount_enter_running(Automount *a) {
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
        Unit *trigger;
        struct stat st;
        int r;

        assert(a);

        /* If the user masked our unit in the meantime, fail */
        if (UNIT(a)->load_state != UNIT_LOADED) {
                log_unit_error(UNIT(a), "Suppressing automount event since unit is no longer loaded.");
                goto fail;
        }

        /* We don't take mount requests anymore if we are supposed to
         * shut down anyway */
        if (unit_stop_pending(UNIT(a))) {
                log_unit_debug(UNIT(a), "Suppressing automount request since unit stop is scheduled.");
                automount_send_ready(a, a->tokens, -EHOSTDOWN);
                automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
                return;
        }

        mkdir_p_label(a->where, a->directory_mode);

        /* Before we do anything, let's see if somebody is playing games with us? */
        if (lstat(a->where, &st) < 0) {
                log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
                goto fail;
        }

        /* The mount unit may have been explicitly started before we got the
         * autofs request. Ack it to unblock anything waiting on the mount point. */
        if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) {
                log_unit_info(UNIT(a), "Automount point already active?");
                automount_send_ready(a, a->tokens, 0);
                return;
        }

        trigger = UNIT_TRIGGER(UNIT(a));
        if (!trigger) {
                log_unit_error(UNIT(a), "Unit to trigger vanished.");
                goto fail;
        }

        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
        if (r < 0) {
                log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                goto fail;
        }

        automount_set_state(a, AUTOMOUNT_RUNNING);
        return;

fail:
        automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}


static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
        struct autofs_dev_ioctl param;

        assert(dev_autofs_fd >= 0);
        assert(ioctl_fd >= 0);

        init_autofs_dev_ioctl(&param);
        param.ioctlfd = ioctl_fd;

        if (status != 0) {
                param.fail.token = token;
                param.fail.status = status;
        } else
                param.ready.token = token;

        if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
                return -errno;

        return 0;
}


static int open_dev_autofs(Manager *m) {
        struct autofs_dev_ioctl param;

        assert(m);

        if (m->dev_autofs_fd >= 0)
                return m->dev_autofs_fd;

        label_fix("/dev/autofs", false, false);

        m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
        if (m->dev_autofs_fd < 0)
                return log_error_errno(errno, "Failed to open /dev/autofs: %m");

        init_autofs_dev_ioctl(&param);
        if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
                m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
                return -errno;
        }

        log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);

        return m->dev_autofs_fd;
}


static int automount_coldplug(Unit *u) {
        Automount *a = AUTOMOUNT(u);
        int r;

        assert(a);
        assert(a->state == AUTOMOUNT_DEAD);

        if (a->deserialized_state == a->state)
                return 0;

        if (IN_SET(a->deserialized_state, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING)) {

                r = automount_set_where(a);
                if (r < 0)
                        return r;

                r = open_dev_autofs(u->manager);
                if (r < 0)
                        return r;

                assert(a->pipe_fd >= 0);

                r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
                if (r < 0)
                        return r;

                (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
                if (a->deserialized_state == AUTOMOUNT_RUNNING) {
                        r = automount_start_expire(a);
                        if (r < 0)
                                log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
                }

                automount_set_state(a, a->deserialized_state);
        }

        return 0;
}


static void skcipher_wmem_wakeup(struct sock *sk)
{
	struct socket_wq *wq;

	if (!skcipher_writable(sk))
		return;

	rcu_read_lock();
	wq = rcu_dereference(sk->sk_wq);
	if (wq_has_sleeper(wq))
		wake_up_interruptible_sync_poll(&wq->wait, POLLIN |
							   POLLRDNORM |
							   POLLRDBAND);
	sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN);
	rcu_read_unlock();
}


static int __init algif_skcipher_init(void)
{
	return af_alg_register_type(&algif_type_skcipher);
}


static int skcipher_wait_for_wmem(struct sock *sk, unsigned flags)
{
	long timeout;
	DEFINE_WAIT(wait);
	int err = -ERESTARTSYS;

	if (flags & MSG_DONTWAIT)
		return -EAGAIN;

	sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk);

	for (;;) {
		if (signal_pending(current))
			break;
		prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE);
		timeout = MAX_SCHEDULE_TIMEOUT;
		if (sk_wait_event(sk, &timeout, skcipher_writable(sk))) {
			err = 0;
			break;
		}
	}
	finish_wait(sk_sleep(sk), &wait);

	return err;
}


DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
{
	unsigned char buf[256];

	switch(label) {
	case 0xf9: /* Graphic Control Extension */
		memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */
		(void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
#if 0
		Gif89.disposal  = (buf[0] >> 2) & 0x7;
		Gif89.inputFlag = (buf[0] >> 1) & 0x1;
		Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
#endif
		if((buf[0] & 0x1) != 0) {
			*Transparent = buf[3];
		}

		while(GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);

		return FALSE;

	default:
		break;
	}

	while(GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);

	return FALSE;
}


_asn1_get_time_der (unsigned type, const unsigned char *der, int der_len, int *ret_len,
		    char *str, int str_size, unsigned flags)
{
  int len_len, str_len;
  unsigned i;
  unsigned sign_count = 0;
  unsigned dot_count = 0;
  const unsigned char *p;

  if (der_len <= 0 || str == NULL)
    return ASN1_DER_ERROR;

  str_len = asn1_get_length_der (der, der_len, &len_len);
  if (str_len <= 0 || str_size < str_len)
    return ASN1_DER_ERROR;

  /* perform some sanity checks on the data */
  if (str_len < 8)
    {
      warn();
      return ASN1_TIME_ENCODING_ERROR;
    }

  if ((flags & ASN1_DECODE_FLAG_STRICT_DER) && !(flags & ASN1_DECODE_FLAG_ALLOW_INCORRECT_TIME))
    {
      p = &der[len_len];
      for (i=0;i<(unsigned)(str_len-1);i++)
         {
           if (isdigit(p[i]) == 0)
             {
               if (type == ASN1_ETYPE_GENERALIZED_TIME)
                 {
                   /* tolerate lax encodings */
                   if (p[i] == '.' && dot_count == 0)
                     {
                       dot_count++;
                       continue;
                     }

               /* This is not really valid DER, but there are
                * structures using that */
                   if (!(flags & ASN1_DECODE_FLAG_STRICT_DER) &&
                       (p[i] == '+' || p[i] == '-') && sign_count == 0)
                     {
                       sign_count++;
                       continue;
                     }
                 }

               warn();
               return ASN1_TIME_ENCODING_ERROR;
             }
         }

      if (sign_count == 0 && p[str_len-1] != 'Z')
        {
          warn();
          return ASN1_TIME_ENCODING_ERROR;
        }
    }
  memcpy (str, der + len_len, str_len);
  str[str_len] = 0;
  *ret_len = str_len + len_len;

  return ASN1_SUCCESS;
}


static void hidp_session_remove(struct l2cap_conn *conn,
				struct l2cap_user *user)
{
	struct hidp_session *session = container_of(user,
						    struct hidp_session,
						    user);

	down_write(&hidp_session_sem);

	hidp_session_terminate(session);

	cancel_work_sync(&session->dev_init);
	if (session->input ||
	    atomic_read(&session->state) > HIDP_SESSION_PREPARING)
		hidp_session_dev_del(session);

	list_del(&session->list);

	up_write(&hidp_session_sem);

	hidp_session_put(session);
}


static void hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
{
	memset(ci, 0, sizeof(*ci));
	bacpy(&ci->bdaddr, &session->bdaddr);

	ci->flags = session->flags;
	ci->state = BT_CONNECTED;

	if (session->input) {
		ci->vendor  = session->input->id.vendor;
		ci->product = session->input->id.product;
		ci->version = session->input->id.version;
		if (session->input->name)
			strlcpy(ci->name, session->input->name, 128);
		else
			strlcpy(ci->name, "HID Boot Device", 128);
	} else if (session->hid) {
		ci->vendor  = session->hid->vendor;
		ci->product = session->hid->product;
		ci->version = session->hid->version;
		strlcpy(ci->name, session->hid->name, 128);
	}
}


static struct hidp_session *__hidp_session_find(const bdaddr_t *bdaddr)
{
	struct hidp_session *session;

	list_for_each_entry(session, &hidp_session_list, list) {
		if (!bacmp(bdaddr, &session->bdaddr))
			return session;
	}

	return NULL;
}


DEFUN(msgs, MSGS, "Display error messages")
{
    cmd_loadBuffer(message_list_panel(), BP_NO_URL, LB_NOLINK);
}


DEFUN(pipesh, PIPE_SHELL, "Execute shell command and display output")
{
    Buffer *buf;
    char *cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("(read shell[pipe])!", "", IN_COMMAND, ShellHist);
    }
    if (cmd != NULL)
	cmd = conv_to_system(cmd);
    if (cmd == NULL || *cmd == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    buf = getpipe(cmd);
    if (buf == NULL) {
	disp_message("Execution failed", TRUE);
	return;
    }
    else {
	buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}


DEFUN(ctrCsrV, CENTER_V, "Center on cursor line")
{
    int offsety;
    if (Currentbuf->firstLine == NULL)
	return;
    offsety = Currentbuf->LINES / 2 - Currentbuf->cursorY;
    if (offsety != 0) {
#if 0
	Currentbuf->currentLine = lineSkip(Currentbuf,
					   Currentbuf->currentLine, offsety,
					   FALSE);
#endif
	Currentbuf->topLine =
	    lineSkip(Currentbuf, Currentbuf->topLine, -offsety, FALSE);
	arrangeLine(Currentbuf);
	displayBuffer(Currentbuf, B_NORMAL);
    }
}


die_oom(size_t bytes)
{
    fprintf(stderr, "Out of memory: %lu bytes unavailable!\n", (unsigned long)bytes);
    exit(1);
}


DEFUN(nextLU, NEXT_LEFT_UP, "Move left or upward to the next hyperlink")
{
    nextX(-1, -1);
}


DEFUN(pgFore, NEXT_PAGE, "Scroll down one page")
{
    if (vi_prec_num)
	nscroll(searchKeyNum() * (Currentbuf->LINES - 1), B_NORMAL);
    else
	nscroll(prec_num ? searchKeyNum() : searchKeyNum()
		* (Currentbuf->LINES - 1), prec_num ? B_SCROLL : B_NORMAL);
}


DEFUN(submitForm, SUBMIT, "Submit form")
{
    _followForm(TRUE);
}


DEFUN(reMark, REG_MARK, "Mark all occurences of a pattern")
{
    Line *l;
    char *str;
    char *p, *p1, *p2;

    if (!use_mark)
	return;
    str = searchKeyData();
    if (str == NULL || *str == '\0') {
	str = inputStrHist("(Mark)Regexp: ", MarkString, TextHist);
	if (str == NULL || *str == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    str = conv_search_string(str, DisplayCharset);
    if ((str = regexCompile(str, 1)) != NULL) {
	disp_message(str, TRUE);
	return;
    }
    MarkString = str;
    for (l = Currentbuf->firstLine; l != NULL; l = l->next) {
	p = l->lineBuf;
	for (;;) {
	    if (regexMatch(p, &l->lineBuf[l->len] - p, p == l->lineBuf) == 1) {
		matchedPosition(&p1, &p2);
		l->propBuf[p1 - l->lineBuf] |= PE_MARK;
		p = p2;
	    }
	    else
		break;
	}
    }

    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}


invoke_browser(char *url)
{
    Str cmd;
    char *browser = NULL;
    int bg = 0, len;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    browser = searchKeyData();
    if (browser == NULL || *browser == '\0') {
	switch (prec_num) {
	case 0:
	case 1:
	    browser = ExtBrowser;
	    break;
	case 2:
	    browser = ExtBrowser2;
	    break;
	case 3:
	    browser = ExtBrowser3;
	    break;
	case 4:
	    browser = ExtBrowser4;
	    break;
	case 5:
	    browser = ExtBrowser5;
	    break;
	case 6:
	    browser = ExtBrowser6;
	    break;
	case 7:
	    browser = ExtBrowser7;
	    break;
	case 8:
	    browser = ExtBrowser8;
	    break;
	case 9:
	    browser = ExtBrowser9;
	    break;
	}
	if (browser == NULL || *browser == '\0') {
	    browser = inputStr("Browse command: ", NULL);
	    if (browser != NULL)
		browser = conv_to_system(browser);
	}
    }
    else {
	browser = conv_to_system(browser);
    }
    if (browser == NULL || *browser == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }

    if ((len = strlen(browser)) >= 2 && browser[len - 1] == '&' &&
	browser[len - 2] != '\\') {
	browser = allocStr(browser, len - 2);
	bg = 1;
    }
    cmd = myExtCommand(browser, shell_quote(url), FALSE);
    Strremovetrailingspaces(cmd);
    fmTerm();
    mySystem(cmd->ptr, bg);
    fmInit();
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}


auxbinFile(char *base)
{
    return expandPath(Strnew_m_charp(w3m_auxbin_dir(), "/", base, NULL)->ptr);
}


DEFUN(movL1, MOVE_LEFT1, "Cursor left. With edge touched, slide")
{
    _movL(1);
}


DEFUN(qquitfm, QUIT, "Quit with confirmation request")
{
    _quitfm(confirm_on_quit);
}


DEFUN(readsh, READ_SHELL, "Execute shell command and display output")
{
    Buffer *buf;
    MySignalHandler(*prevtrap) ();
    char *cmd;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    cmd = searchKeyData();
    if (cmd == NULL || *cmd == '\0') {
	cmd = inputLineHist("(read shell)!", "", IN_COMMAND, ShellHist);
    }
    if (cmd != NULL)
	cmd = conv_to_system(cmd);
    if (cmd == NULL || *cmd == '\0') {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    prevtrap = mySignal(SIGINT, intTrap);
    crmode();
    buf = getshell(cmd);
    mySignal(SIGINT, prevtrap);
    term_raw();
    if (buf == NULL) {
	/* FIXME: gettextize? */
	disp_message("Execution failed", TRUE);
	return;
    }
    else {
	buf->bufferprop |= (BP_INTERNAL | BP_NO_URL);
	if (buf->type == NULL)
	    buf->type = "text/plain";
	pushBuffer(buf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}


DEFUN(prevVA, PREV_VISITED, "Move to the previous visited hyperlink")
{
    _prevA(TRUE);
}


DEFUN(adBmark, ADD_BOOKMARK, "Add current page to bookmarks")
{
    Str tmp;
    FormList *request;

    tmp = Sprintf("mode=panel&cookie=%s&bmark=%s&url=%s&title=%s"
#ifdef USE_M17N
		    "&charset=%s"
#endif
		    ,
		  (Str_form_quote(localCookie()))->ptr,
		  (Str_form_quote(Strnew_charp(BookmarkFile)))->ptr,
		  (Str_form_quote(parsedURL2Str(&Currentbuf->currentURL)))->
		  ptr,
#ifdef USE_M17N
		  (Str_form_quote(wc_conv_strict(Currentbuf->buffername,
						 InnerCharset,
						 BookmarkCharset)))->ptr,
		  wc_ces_to_charset(BookmarkCharset));
#else
		  (Str_form_quote(Strnew_charp(Currentbuf->buffername)))->ptr);
#endif
    request = newFormList(NULL, "post", NULL, NULL, NULL, NULL, NULL);
    request->body = tmp->ptr;
    request->length = tmp->length;
    cmd_loadURL("file:///$LIB/" W3MBOOKMARK_CMDNAME, NULL, NO_REFERER,
		request);
}


cur_real_linenumber(Buffer *buf)
{
    Line *l, *cur = buf->currentLine;
    int n;

    if (!cur)
	return 1;
    n = cur->real_linenumber ? cur->real_linenumber : 1;
    for (l = buf->firstLine; l && l != cur && l->real_linenumber == 0; l = l->next) {	/* header */
	if (l->bpos == 0)
	    n++;
    }
    return n;
}


escKeyProc(int c, int esc, unsigned char *map)
{
    if (CurrentKey >= 0 && CurrentKey & K_MULTI) {
	unsigned char **mmap;
	mmap = (unsigned char **)getKeyData(MULTI_KEY(CurrentKey));
	if (!mmap)
	    return;
	switch (esc) {
	case K_ESCD:
	    map = mmap[3];
	    break;
	case K_ESCB:
	    map = mmap[2];
	    break;
	case K_ESC:
	    map = mmap[1];
	    break;
	default:
	    map = mmap[0];
	    break;
	}
	esc |= (CurrentKey & ~0xFFFF);
    }
    CurrentKey = esc | c;
    w3mFuncList[(int)map[c]].func();
}


gotoLabel(char *label)
{
    Buffer *buf;
    Anchor *al;
    int i;

    al = searchURLLabel(Currentbuf, label);
    if (al == NULL) {
	/* FIXME: gettextize? */
	disp_message(Sprintf("%s is not found", label)->ptr, TRUE);
	return;
    }
    buf = newBuffer(Currentbuf->width);
    copyBuffer(buf, Currentbuf);
    for (i = 0; i < MAX_LB; i++)
	buf->linkBuffer[i] = NULL;
    buf->currentURL.label = allocStr(label, -1);
    pushHashHist(URLHist, parsedURL2Str(&buf->currentURL)->ptr);
    (*buf->clone)++;
    pushBuffer(buf);
    gotoLine(Currentbuf, al->start.line);
    if (label_topline)
	Currentbuf->topLine = lineSkip(Currentbuf, Currentbuf->topLine,
				       Currentbuf->currentLine->linenumber
				       - Currentbuf->topLine->linenumber,
				       FALSE);
    Currentbuf->pos = al->start.pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
    return;
}


DEFUN(setEnv, SETENV, "Set environment variable")
{
    char *env;
    char *var, *value;

    CurrentKeyData = NULL;	/* not allowed in w3m-control: */
    env = searchKeyData();
    if (env == NULL || *env == '\0' || strchr(env, '=') == NULL) {
	if (env != NULL && *env != '\0')
	    env = Sprintf("%s=", env)->ptr;
	env = inputStrHist("Set environ: ", env, TextHist);
	if (env == NULL || *env == '\0') {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
    }
    if ((value = strchr(env, '=')) != NULL && value > env) {
	var = allocStr(env, value - env);
	value++;
	set_environ(var, value);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}


anchorMn(Anchor *(*menu_func) (Buffer *), int go)
{
    Anchor *a;
    BufferPoint *po;

    if (!Currentbuf->href || !Currentbuf->hmarklist)
	return;
    a = menu_func(Currentbuf);
    if (!a || a->hseq < 0)
	return;
    po = &Currentbuf->hmarklist->marks[a->hseq];
    gotoLine(Currentbuf, po->line);
    Currentbuf->pos = po->pos;
    arrangeCursor(Currentbuf);
    displayBuffer(Currentbuf, B_NORMAL);
    if (go)
	followA();
}


repBuffer(Buffer *oldbuf, Buffer *buf)
{
    Firstbuf = replaceBuffer(Firstbuf, oldbuf, buf);
    Currentbuf = buf;
}


DEFUN(reload, RELOAD, "Load current document anew")
{
    Buffer *buf, *fbuf = NULL, sbuf;
#ifdef USE_M17N
    wc_ces old_charset;
#endif
    Str url;
    FormList *request;
    int multipart;

    if (Currentbuf->bufferprop & BP_INTERNAL) {
	if (!strcmp(Currentbuf->buffername, DOWNLOAD_LIST_TITLE)) {
	    ldDL();
	    return;
	}
	/* FIXME: gettextize? */
	disp_err_message("Can't reload...", TRUE);
	return;
    }
    if (Currentbuf->currentURL.scheme == SCM_LOCAL &&
	!strcmp(Currentbuf->currentURL.file, "-")) {
	/* file is std input */
	/* FIXME: gettextize? */
	disp_err_message("Can't reload stdin", TRUE);
	return;
    }
    copyBuffer(&sbuf, Currentbuf);
    if (Currentbuf->bufferprop & BP_FRAME &&
	(fbuf = Currentbuf->linkBuffer[LB_N_FRAME])) {
	if (fmInitialized) {
	    message("Rendering frame", 0, 0);
	    refresh();
	}
	if (!(buf = renderFrame(fbuf, 1))) {
	    displayBuffer(Currentbuf, B_NORMAL);
	    return;
	}
	if (fbuf->linkBuffer[LB_FRAME]) {
	    if (buf->sourcefile &&
		fbuf->linkBuffer[LB_FRAME]->sourcefile &&
		!strcmp(buf->sourcefile,
			fbuf->linkBuffer[LB_FRAME]->sourcefile))
		fbuf->linkBuffer[LB_FRAME]->sourcefile = NULL;
	    delBuffer(fbuf->linkBuffer[LB_FRAME]);
	}
	fbuf->linkBuffer[LB_FRAME] = buf;
	buf->linkBuffer[LB_N_FRAME] = fbuf;
	pushBuffer(buf);
	Currentbuf = buf;
	if (Currentbuf->firstLine) {
	    COPY_BUFROOT(Currentbuf, &sbuf);
	    restorePosition(Currentbuf, &sbuf);
	}
	displayBuffer(Currentbuf, B_FORCE_REDRAW);
	return;
    }
    else if (Currentbuf->frameset != NULL)
	fbuf = Currentbuf->linkBuffer[LB_FRAME];
    multipart = 0;
    if (Currentbuf->form_submit) {
	request = Currentbuf->form_submit->parent;
	if (request->method == FORM_METHOD_POST
	    && request->enctype == FORM_ENCTYPE_MULTIPART) {
	    Str query;
	    struct stat st;
	    multipart = 1;
	    query_from_followform(&query, Currentbuf->form_submit, multipart);
	    stat(request->body, &st);
	    request->length = st.st_size;
	}
    }
    else {
	request = NULL;
    }
    url = parsedURL2Str(&Currentbuf->currentURL);
    /* FIXME: gettextize? */
    message("Reloading...", 0, 0);
    refresh();
#ifdef USE_M17N
    old_charset = DocumentCharset;
    if (Currentbuf->document_charset != WC_CES_US_ASCII)
	DocumentCharset = Currentbuf->document_charset;
#endif
    SearchHeader = Currentbuf->search_header;
    DefaultType = Currentbuf->real_type;
    buf = loadGeneralFile(url->ptr, NULL, NO_REFERER, RG_NOCACHE, request);
#ifdef USE_M17N
    DocumentCharset = old_charset;
#endif
    SearchHeader = FALSE;
    DefaultType = NULL;

    if (multipart)
	unlink(request->body);
    if (buf == NULL) {
	/* FIXME: gettextize? */
	disp_err_message("Can't reload...", TRUE);
	return;
    }
    else if (buf == NO_BUFFER) {
	displayBuffer(Currentbuf, B_NORMAL);
	return;
    }
    if (fbuf != NULL)
	Firstbuf = deleteBuffer(Firstbuf, fbuf);
    repBuffer(Currentbuf, buf);
    if ((buf->type != NULL) && (sbuf.type != NULL) &&
	((!strcasecmp(buf->type, "text/plain") &&
	  is_html_type(sbuf.type)) ||
	 (is_html_type(buf->type) &&
	  !strcasecmp(sbuf.type, "text/plain")))) {
	vwSrc();
	if (Currentbuf != buf)
	    Firstbuf = deleteBuffer(Firstbuf, buf);
    }
    Currentbuf->search_header = sbuf.search_header;
    Currentbuf->form_submit = sbuf.form_submit;
    if (Currentbuf->firstLine) {
	COPY_BUFROOT(Currentbuf, &sbuf);
	restorePosition(Currentbuf, &sbuf);
    }
    displayBuffer(Currentbuf, B_FORCE_REDRAW);
}


DEFUN(sgrmouse, SGRMOUSE, "SGR 1006 mouse operation")
{
    int btn = 0, x = 0, y = 0;
    unsigned char c;

    do {
	c = getch();
	if (IS_DIGIT(c))
	    btn = btn * 10 + c - '0';
	else if (c == ';')
	    break;
	else
	    return;
    } while (1);

#if defined(__CYGWIN__) && CYGWIN_VERSION_DLL_MAJOR < 1005
    if (cygwin_mouse_btn_swapped) {
	if (btn == MOUSE_BTN2_DOWN)
	    btn = MOUSE_BTN3_DOWN;
	else if (btn == MOUSE_BTN3_DOWN)
	    btn = MOUSE_BTN2_DOWN;
    };
#endif

    do {
	c = getch();
	if (IS_DIGIT(c))
	    x = x * 10 + c - '0';
	else if (c == ';')
	    break;
	else
	  return;
    } while (1);
    if (x>0) x--;

    do {
	c = getch();
	if (IS_DIGIT(c))
	    y = y * 10 + c - '0';
	else if (c == 'M')
	    break;
	else if (c == 'm') {
	    btn |= 3;
	    break;
	} else
    return;
    } while (1);
    if (y>0) y--;

    if (x < 0 || x >= COLS || y < 0 || y > LASTLINE)
	return;
    process_mouse(btn, x, y);
}


DEFUN(pcmap, PCMAP, "pcmap")
{
    w3mFuncList[(int)PcKeymap[(int)getch()]].func();
}


etcFile(char *base)
{
    return expandPath(Strnew_m_charp(w3m_etc_dir(), "/", base, NULL)->ptr);
}


loadSiteconf(void)
{
    char *efname;
    FILE *fp;
    Str line;
    struct siteconf_rec *ent = NULL;

    siteconf_head = NULL;
    if (!siteconf_file)
	return;
    if ((efname = expandPath(siteconf_file)) == NULL)
	return;
    fp = fopen(efname, "r");
    if (fp == NULL)
	return;
    while (line = Strfgets(fp), line->length > 0) {
	char *p, *s;

	Strchop(line);
	p = line->ptr;
	SKIP_BLANKS(p);
	if (*p == '#' || *p == '\0')
	    continue;
	s = getWord(&p);

	/* The "url" begins a new record. */
	if (strcmp(s, "url") == 0) {
	    char *url, *opt;
	    struct siteconf_rec *newent;

	    /* First, register the current record. */
	    if (ent) {
		ent->next = siteconf_head;
		siteconf_head = ent;
		ent = NULL;
	    }

	    /* Second, create a new record. */
	    newent = newSiteconfRec();
	    url = getRegexWord((const char **)&p, &newent->re_url);
	    opt = getWord(&p);
	    SKIP_BLANKS(p);
	    if (!newent->re_url) {
		ParsedURL pu;
		if (!url || !*url)
		    continue;
		parseURL2(url, &pu, NULL);
		newent->url = parsedURL2Str(&pu)->ptr;
	    }
	    /* If we have an extra or unknown option, ignore this record
	     * for future extensions. */
	    if (strcmp(opt, "exact") == 0) {
		newent->url_exact = TRUE;
	    }
	    else if (*opt != 0)
		    continue;
	    if (*p)
		continue;
	    ent = newent;
	    continue;
	}

	/* If the current record is broken, skip to the next "url". */
	if (!ent)
	    continue;

	/* Fill the new record. */
	if (strcmp(s, "substitute_url") == 0) {
	    ent->substitute_url = getQWord(&p);
	    SCONF_SET(ent, SCONF_SUBSTITUTE_URL);
	}
#ifdef USE_M17N
	else if (strcmp(s, "url_charset") == 0) {
	    char *charset = getWord(&p);
	    ent->url_charset = (charset && *charset) ?
		wc_charset_to_ces(charset) : 0;
	    SCONF_SET(ent, SCONF_URL_CHARSET);
	}
#endif /* USE_M17N */
	else if (strcmp(s, "no_referer_from") == 0) {
	    ent->no_referer_from = str_to_bool(getWord(&p), 0);
	    SCONF_SET(ent, SCONF_NO_REFERER_FROM);
	}
	else if (strcmp(s, "no_referer_to") == 0) {
	    ent->no_referer_to = str_to_bool(getWord(&p), 0);
	    SCONF_SET(ent, SCONF_NO_REFERER_TO);
	}
    }
    if (ent) {
	ent->next = siteconf_head;
	siteconf_head = ent;
	ent = NULL;
    }
    fclose(fp);
}


DEFUN(col1L, LEFT, "Shift screen one column left")
{
    Buffer *buf = Currentbuf;
    Line *l = buf->currentLine;
    int j, n = searchKeyNum();

    if (l == NULL)
	return;
    for (j = 0; j < n; j++) {
	if (buf->currentColumn == 0)
	    break;
	columnSkip(Currentbuf, -1);
	shiftvisualpos(Currentbuf, -1);
    }
    displayBuffer(Currentbuf, B_NORMAL);
}


delBuffer(Buffer *buf)
{
    if (buf == NULL)
	return;
    if (Currentbuf == buf)
	Currentbuf = buf->nextBuffer;
    Firstbuf = deleteBuffer(Firstbuf, buf);
    if (!Currentbuf)
	Currentbuf = Firstbuf;
}


str_to_bool(char *value, int old)
{
    if (value == NULL)
	return 1;
    switch (TOLOWER(*value)) {
    case '0':
    case 'f':			/* false */
    case 'n':			/* no */
    case 'u':			/* undef */
	return 0;
    case 'o':
	if (TOLOWER(value[1]) == 'f')	/* off */
	    return 0;
	return 1;		/* on */
    case 't':
	if (TOLOWER(value[1]) == 'o')	/* toggle */
	    return !old;
	return 1;		/* true */
    case '!':
    case 'r':			/* reverse */
    case 'x':			/* exchange */
	return !old;
    }
    return 1;
}


static void pcrypt_fini_padata(struct padata_pcrypt *pcrypt)
{
	free_cpumask_var(pcrypt->cb_cpumask->mask);
	kfree(pcrypt->cb_cpumask);

	padata_stop(pcrypt->pinst);
	padata_unregister_cpumask_notifier(pcrypt->pinst, &pcrypt->nblock);
	destroy_workqueue(pcrypt->wq);
	padata_free(pcrypt->pinst);
}


static int __init pcrypt_init(void)
{
	int err = -ENOMEM;

	pcrypt_kset = kset_create_and_add("pcrypt", NULL, kernel_kobj);
	if (!pcrypt_kset)
		goto err;

	err = pcrypt_init_padata(&pencrypt, "pencrypt");
	if (err)
		goto err_unreg_kset;

	err = pcrypt_init_padata(&pdecrypt, "pdecrypt");
	if (err)
		goto err_deinit_pencrypt;

	padata_start(pencrypt.pinst);
	padata_start(pdecrypt.pinst);

	return crypto_register_template(&pcrypt_tmpl);

err_deinit_pencrypt:
	pcrypt_fini_padata(&pencrypt);
err_unreg_kset:
	kset_unregister(pcrypt_kset);
err:
	return err;
}


static void pcrypt_aead_exit_tfm(struct crypto_aead *tfm)
{
	struct pcrypt_aead_ctx *ctx = crypto_aead_ctx(tfm);

	crypto_free_aead(ctx->child);
}


static js_Ast *assignment(js_State *J, int notin)
{
	js_Ast *a = conditional(J, notin);
	INCREC();
	if (jsP_accept(J, '=')) a = EXP2(ASS, a, assignment(J, notin));
	else if (jsP_accept(J, TK_MUL_ASS)) a = EXP2(ASS_MUL, a, assignment(J, notin));
	else if (jsP_accept(J, TK_DIV_ASS)) a = EXP2(ASS_DIV, a, assignment(J, notin));
	else if (jsP_accept(J, TK_MOD_ASS)) a = EXP2(ASS_MOD, a, assignment(J, notin));
	else if (jsP_accept(J, TK_ADD_ASS)) a = EXP2(ASS_ADD, a, assignment(J, notin));
	else if (jsP_accept(J, TK_SUB_ASS)) a = EXP2(ASS_SUB, a, assignment(J, notin));
	else if (jsP_accept(J, TK_SHL_ASS)) a = EXP2(ASS_SHL, a, assignment(J, notin));
	else if (jsP_accept(J, TK_SHR_ASS)) a = EXP2(ASS_SHR, a, assignment(J, notin));
	else if (jsP_accept(J, TK_USHR_ASS)) a = EXP2(ASS_USHR, a, assignment(J, notin));
	else if (jsP_accept(J, TK_AND_ASS)) a = EXP2(ASS_BITAND, a, assignment(J, notin));
	else if (jsP_accept(J, TK_XOR_ASS)) a = EXP2(ASS_BITXOR, a, assignment(J, notin));
	else if (jsP_accept(J, TK_OR_ASS)) a = EXP2(ASS_BITOR, a, assignment(J, notin));
	DECREC();
	return a;
}


js_Ast *jsP_parsefunction(js_State *J, const char *filename, const char *params, const char *body)
{
	js_Ast *p = NULL;
	if (params) {
		jsY_initlex(J, filename, params);
		jsP_next(J);
		J->astdepth = 0;
		p = parameters(J);
	}
	return EXP3(FUN, NULL, p, jsP_parse(J, filename, body));
}


static js_Ast *postfix(js_State *J)
{
	js_Ast *a = callexp(J);
	if (!J->newline && jsP_accept(J, TK_INC)) return EXP1(POSTINC, a);
	if (!J->newline && jsP_accept(J, TK_DEC)) return EXP1(POSTDEC, a);
	return a;
}


int acpi_smbus_write(struct acpi_smb_hc *hc, u8 protocol, u8 address,
		     u8 command, u8 *data, u8 length)
{
	return acpi_smbus_transaction(hc, protocol, address, command, data, length);
}


static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
{
	if (wait_event_timeout(hc->wait, hc->done, msecs_to_jiffies(timeout)))
		return 0;
	return -ETIME;
}


static void i8042_port_close(struct serio *serio)
{
	int irq_bit;
	int disable_bit;
	const char *port_name;

	if (serio == i8042_ports[I8042_AUX_PORT_NO].serio) {
		irq_bit = I8042_CTR_AUXINT;
		disable_bit = I8042_CTR_AUXDIS;
		port_name = "AUX";
	} else {
		irq_bit = I8042_CTR_KBDINT;
		disable_bit = I8042_CTR_KBDDIS;
		port_name = "KBD";
	}

	i8042_ctr &= ~irq_bit;
	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
		pr_warn("Can't write CTR while closing %s port\n", port_name);

	udelay(50);

	i8042_ctr &= ~disable_bit;
	i8042_ctr |= irq_bit;
	if (i8042_command(&i8042_ctr, I8042_CMD_CTL_WCTR))
		pr_err("Can't reactivate %s port\n", port_name);

	/*
	 * See if there is any data appeared while we were messing with
	 * port state.
	 */
	i8042_interrupt(0, NULL);
}


static int i8042_controller_selftest(void)
{
	unsigned char param;
	int i = 0;

	/*
	 * We try this 5 times; on some really fragile systems this does not
	 * take the first time...
	 */
	do {

		if (i8042_command(&param, I8042_CMD_CTL_TEST)) {
			pr_err("i8042 controller selftest timeout\n");
			return -ENODEV;
		}

		if (param == I8042_RET_CTL_TEST)
			return 0;

		dbg("i8042 controller selftest: %#x != %#x\n",
		    param, I8042_RET_CTL_TEST);
		msleep(50);
	} while (i++ < 5);

#ifdef CONFIG_X86
	/*
	 * On x86, we don't fail entire i8042 initialization if controller
	 * reset fails in hopes that keyboard port will still be functional
	 * and user will still get a working keyboard. This is especially
	 * important on netbooks. On other arches we trust hardware more.
	 */
	pr_info("giving up on controller selftest, continuing anyway...\n");
	return 0;
#else
	pr_err("i8042 controller selftest failed\n");
	return -EIO;
#endif
}


static int i8042_pm_resume_noirq(struct device *dev)
{
	if (!pm_resume_via_firmware())
		i8042_interrupt(0, NULL);

	return 0;
}


static int __init i8042_create_aux_port(int idx)
{
	struct serio *serio;
	int port_no = idx < 0 ? I8042_AUX_PORT_NO : I8042_MUX_PORT_NO + idx;
	struct i8042_port *port = &i8042_ports[port_no];

	serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
	if (!serio)
		return -ENOMEM;

	serio->id.type		= SERIO_8042;
	serio->write		= i8042_aux_write;
	serio->start		= i8042_start;
	serio->stop		= i8042_stop;
	serio->ps2_cmd_mutex	= &i8042_mutex;
	serio->port_data	= port;
	serio->dev.parent	= &i8042_platform_device->dev;
	if (idx < 0) {
		strlcpy(serio->name, "i8042 AUX port", sizeof(serio->name));
		strlcpy(serio->phys, I8042_AUX_PHYS_DESC, sizeof(serio->phys));
		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
			sizeof(serio->firmware_id));
		serio->close = i8042_port_close;
	} else {
		snprintf(serio->name, sizeof(serio->name), "i8042 AUX%d port", idx);
		snprintf(serio->phys, sizeof(serio->phys), I8042_MUX_PHYS_DESC, idx + 1);
		strlcpy(serio->firmware_id, i8042_aux_firmware_id,
			sizeof(serio->firmware_id));
	}

	port->serio = serio;
	port->mux = idx;
	port->irq = I8042_AUX_IRQ;

	return 0;
}


static void __init i8042_free_kbd_port(void)
{
	kfree(i8042_ports[I8042_KBD_PORT_NO].serio);
	i8042_ports[I8042_KBD_PORT_NO].serio = NULL;
}


static int read_config_file(const char **config_dirs, const char *fn, bool ignore_enoent, bool *invalid_config) {
        _cleanup_fclose_ FILE *_f = NULL;
        FILE *f;
        char line[LINE_MAX];
        Iterator iterator;
        unsigned v = 0;
        Item *i;
        int r = 0;

        assert(fn);

        if (streq(fn, "-")) {
                log_debug("Reading config from stdin.");
                fn = "<stdin>";
                f = stdin;
        } else {
                r = search_and_fopen(fn, "re", arg_root, config_dirs, &_f);
                if (r < 0) {
                        if (ignore_enoent && r == -ENOENT) {
                                log_debug_errno(r, "Failed to open \"%s\", ignoring: %m", fn);
                                return 0;
                        }

                        return log_error_errno(r, "Failed to open '%s': %m", fn);
                }
                log_debug("Reading config file \"%s\".", fn);
                f = _f;
        }

        FOREACH_LINE(line, f, break) {
                char *l;
                int k;
                bool invalid_line = false;

                v++;

                l = strstrip(line);
                if (IN_SET(*l, 0, '#'))
                        continue;

                k = parse_line(fn, v, l, &invalid_line);
                if (k < 0) {
                        if (invalid_line)
                                /* Allow reporting with a special code if the caller requested this */
                                *invalid_config = true;
                        else if (r == 0)
                                /* The first error becomes our return value */
                                r = k;
                }
        }

        /* we have to determine age parameter for each entry of type X */
        ORDERED_HASHMAP_FOREACH(i, globs, iterator) {
                Iterator iter;
                Item *j, *candidate_item = NULL;

                if (i->type != IGNORE_DIRECTORY_PATH)
                        continue;

                ORDERED_HASHMAP_FOREACH(j, items, iter) {
                        if (!IN_SET(j->type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA))
                                continue;

                        if (path_equal(j->path, i->path)) {
                                candidate_item = j;
                                break;
                        }

                        if ((!candidate_item && path_startswith(i->path, j->path)) ||
                            (candidate_item && path_startswith(j->path, candidate_item->path) && (fnmatch(i->path, j->path, FNM_PATHNAME | FNM_PERIOD) == 0)))
                                candidate_item = j;
                }

                if (candidate_item && candidate_item->age_set) {
                        i->age = candidate_item->age;
                        i->age_set = true;
                }
        }

        if (ferror(f)) {
                log_error_errno(errno, "Failed to read from file %s: %m", fn);
                if (r == 0)
                        r = -EIO;
        }

        return r;
}


static int item_do_children(Item *i, const char *path, action_t action) {
        _cleanup_closedir_ DIR *d;
        struct dirent *de;
        int r = 0;

        assert(i);
        assert(path);

        /* This returns the first error we run into, but nevertheless
         * tries to go on */

        d = opendir_nomod(path);
        if (!d)
                return IN_SET(errno, ENOENT, ENOTDIR, ELOOP) ? 0 : -errno;

        FOREACH_DIRENT_ALL(de, d, r = -errno) {
                _cleanup_free_ char *p = NULL;
                int q;

                if (dot_or_dot_dot(de->d_name))
                        continue;

                p = strjoin(path, "/", de->d_name);
                if (!p)
                        return -ENOMEM;

                q = action(i, p);
                if (q < 0 && q != -ENOENT && r == 0)
                        r = q;

                if (IN_SET(de->d_type, DT_UNKNOWN, DT_DIR)) {
                        q = item_do_children(i, p, action);
                        if (q < 0 && r == 0)
                                r = q;
                }
        }

        return r;
}


static void item_free_contents(Item *i) {
        assert(i);
        free(i->path);
        free(i->argument);
        strv_free(i->xattrs);

#if HAVE_ACL
        acl_free(i->acl_access);
        acl_free(i->acl_default);
#endif
}


static int process_item(Item *i) {
        int r, q, p, t = 0;
        _cleanup_free_ char *prefix = NULL;

        assert(i);

        if (i->done)
                return 0;

        i->done = true;

        prefix = malloc(strlen(i->path) + 1);
        if (!prefix)
                return log_oom();

        PATH_FOREACH_PREFIX(prefix, i->path) {
                ItemArray *j;

                j = ordered_hashmap_get(items, prefix);
                if (j) {
                        int s;

                        s = process_item_array(j);
                        if (s < 0 && t == 0)
                                t = s;
                }
        }

        if (chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS, NULL) == -EREMOTE)
                return t;

        r = arg_create ? create_item(i) : 0;
        q = arg_remove ? remove_item(i) : 0;
        p = arg_clean ? clean_item(i) : 0;

        return t < 0 ? t :
                r < 0 ? r :
                q < 0 ? q :
                p;
}


void stub_enqueue_ret_unlink(struct stub_device *sdev, __u32 seqnum,
			     __u32 status)
{
	struct stub_unlink *unlink;

	unlink = kzalloc(sizeof(struct stub_unlink), GFP_ATOMIC);
	if (!unlink) {
		usbip_event_add(&sdev->ud, VDEV_EVENT_ERROR_MALLOC);
		return;
	}

	unlink->seqnum = seqnum;
	unlink->status = status;

	list_add_tail(&unlink->list, &sdev->unlink_tx);
}


int bnx2x_setup_leading(struct bnx2x *bp)
{
	if (IS_PF(bp))
		return bnx2x_setup_queue(bp, &bp->fp[0], true);
	else /* VF */
		return bnx2x_vfpf_setup_q(bp, &bp->fp[0], true);
}


static void bnx2x_gunzip_end(struct bnx2x *bp)
{
	if (bp->strm) {
		vfree(bp->strm->workspace);
		kfree(bp->strm);
		bp->strm = NULL;
	}

	if (bp->gunzip_buf) {
		dma_free_coherent(&bp->pdev->dev, FW_BUF_SIZE, bp->gunzip_buf,
				  bp->gunzip_mapping);
		bp->gunzip_buf = NULL;
	}
}


static void bnx2x_init_sp_ring(struct bnx2x *bp)
{
	spin_lock_init(&bp->spq_lock);
	atomic_set(&bp->cq_spq_left, MAX_SPQ_PENDING);

	bp->spq_prod_idx = 0;
	bp->dsb_sp_prod = BNX2X_SP_DSB_INDEX;
	bp->spq_prod_bd = bp->spq;
	bp->spq_last_bd = bp->spq_prod_bd + MAX_SP_DESC_CNT;
}


static void bnx2x_e1h_disable(struct bnx2x *bp)
{
	int port = BP_PORT(bp);

	bnx2x_tx_disable(bp);

	REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
}


int bnx2x_del_all_macs(struct bnx2x *bp,
		       struct bnx2x_vlan_mac_obj *mac_obj,
		       int mac_type, bool wait_for_comp)
{
	int rc;
	unsigned long ramrod_flags = 0, vlan_mac_flags = 0;

	/* Wait for completion of requested */
	if (wait_for_comp)
		__set_bit(RAMROD_COMP_WAIT, &ramrod_flags);

	/* Set the mac type of addresses we want to clear */
	__set_bit(mac_type, &vlan_mac_flags);

	rc = mac_obj->delete_all(bp, mac_obj, &vlan_mac_flags, &ramrod_flags);
	if (rc < 0)
		BNX2X_ERR("Failed to delete MACs: %d\n", rc);

	return rc;
}


u32 bnx2x_dmae_opcode(struct bnx2x *bp, u8 src_type, u8 dst_type,
			     bool with_comp, u8 comp_type)
{
	u32 opcode = 0;

	opcode |= ((src_type << DMAE_COMMAND_SRC_SHIFT) |
		   (dst_type << DMAE_COMMAND_DST_SHIFT));

	opcode |= (DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET);

	opcode |= (BP_PORT(bp) ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0);
	opcode |= ((BP_VN(bp) << DMAE_CMD_E1HVN_SHIFT) |
		   (BP_VN(bp) << DMAE_COMMAND_DST_VN_SHIFT));
	opcode |= (DMAE_COM_SET_ERR << DMAE_COMMAND_ERR_POLICY_SHIFT);

#ifdef __BIG_ENDIAN
	opcode |= DMAE_CMD_ENDIANITY_B_DW_SWAP;
#else
	opcode |= DMAE_CMD_ENDIANITY_DW_SWAP;
#endif
	if (with_comp)
		opcode = bnx2x_dmae_opcode_add_comp(opcode, comp_type);
	return opcode;
}


static void bnx2x_attn_int_deasserted3(struct bnx2x *bp, u32 attn)
{
	u32 val;

	if (attn & EVEREST_GEN_ATTN_IN_USE_MASK) {

		if (attn & BNX2X_PMF_LINK_ASSERT) {
			int func = BP_FUNC(bp);

			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_12 + func*4, 0);
			bnx2x_read_mf_cfg(bp);
			bp->mf_config[BP_VN(bp)] = MF_CFG_RD(bp,
					func_mf_config[BP_ABS_FUNC(bp)].config);
			val = SHMEM_RD(bp,
				       func_mb[BP_FW_MB_IDX(bp)].drv_status);

			if (val & (DRV_STATUS_DCC_EVENT_MASK |
				   DRV_STATUS_OEM_EVENT_MASK))
				bnx2x_oem_event(bp,
					(val & (DRV_STATUS_DCC_EVENT_MASK |
						DRV_STATUS_OEM_EVENT_MASK)));

			if (val & DRV_STATUS_SET_MF_BW)
				bnx2x_set_mf_bw(bp);

			if (val & DRV_STATUS_DRV_INFO_REQ)
				bnx2x_handle_drv_info_req(bp);

			if (val & DRV_STATUS_VF_DISABLED)
				bnx2x_schedule_iov_task(bp,
							BNX2X_IOV_HANDLE_FLR);

			if ((bp->port.pmf == 0) && (val & DRV_STATUS_PMF))
				bnx2x_pmf_update(bp);

			if (bp->port.pmf &&
			    (val & DRV_STATUS_DCBX_NEGOTIATION_RESULTS) &&
				bp->dcbx_enabled > 0)
				/* start dcbx state machine */
				bnx2x_dcbx_set_params(bp,
					BNX2X_DCBX_STATE_NEG_RECEIVED);
			if (val & DRV_STATUS_AFEX_EVENT_MASK)
				bnx2x_handle_afex_cmd(bp,
					val & DRV_STATUS_AFEX_EVENT_MASK);
			if (val & DRV_STATUS_EEE_NEGOTIATION_RESULTS)
				bnx2x_handle_eee_event(bp);

			if (val & DRV_STATUS_OEM_UPDATE_SVID)
				bnx2x_handle_update_svid_cmd(bp);

			if (bp->link_vars.periodic_flags &
			    PERIODIC_FLAGS_LINK_EVENT) {
				/*  sync with link */
				bnx2x_acquire_phy_lock(bp);
				bp->link_vars.periodic_flags &=
					~PERIODIC_FLAGS_LINK_EVENT;
				bnx2x_release_phy_lock(bp);
				if (IS_MF(bp))
					bnx2x_link_sync_notify(bp);
				bnx2x_link_report(bp);
			}
			/* Always call it here: bnx2x_link_report() will
			 * prevent the link indication duplication.
			 */
			bnx2x__link_status_update(bp);
		} else if (attn & BNX2X_MC_ASSERT_BITS) {

			BNX2X_ERR("MC assert!\n");
			bnx2x_mc_assert(bp);
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_10, 0);
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_9, 0);
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_8, 0);
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_7, 0);
			bnx2x_panic();

		} else if (attn & BNX2X_MCP_ASSERT) {

			BNX2X_ERR("MCP assert!\n");
			REG_WR(bp, MISC_REG_AEU_GENERAL_ATTN_11, 0);
			bnx2x_fw_dump(bp);

		} else
			BNX2X_ERR("Unknown HW assert! (attn 0x%x)\n", attn);
	}

	if (attn & EVEREST_LATCHED_ATTN_IN_USE_MASK) {
		BNX2X_ERR("LATCHED attention 0x%08x (masked)\n", attn);
		if (attn & BNX2X_GRC_TIMEOUT) {
			val = CHIP_IS_E1(bp) ? 0 :
					REG_RD(bp, MISC_REG_GRC_TIMEOUT_ATTN);
			BNX2X_ERR("GRC time-out 0x%08x\n", val);
		}
		if (attn & BNX2X_GRC_RSV) {
			val = CHIP_IS_E1(bp) ? 0 :
					REG_RD(bp, MISC_REG_GRC_RSV_ATTN);
			BNX2X_ERR("GRC reserved 0x%08x\n", val);
		}
		REG_WR(bp, MISC_REG_AEU_CLR_LATCH_SIGNAL, 0x7ff);
	}
}


static void bnx2x_clear_reset_global(struct bnx2x *bp)
{
	u32 val;
	bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
	val = REG_RD(bp, BNX2X_RECOVERY_GLOB_REG);
	REG_WR(bp, BNX2X_RECOVERY_GLOB_REG, val & (~BNX2X_GLOBAL_RESET_BIT));
	bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_RECOVERY_REG);
}


static void bnx2x_init_tx_rings_cnic(struct bnx2x *bp)
{
	int i;

	for_each_tx_queue_cnic(bp, i)
		bnx2x_init_tx_ring_one(bp->fp[i].txdata_ptr[0]);
}


static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
	struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);

	if (!netif_running(bp->dev)) {
		DP(BNX2X_MSG_PTP,
		   "PTP adjtime called while the interface is down\n");
		return -ENETDOWN;
	}

	DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta);

	timecounter_adjtime(&bp->timecounter, delta);

	return 0;
}


static void bnx2x_e1h_enable(struct bnx2x *bp)
{
	int port = BP_PORT(bp);

	if (!(IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)))
		REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port * 8, 1);

	/* Tx queue should be only re-enabled */
	netif_tx_wake_all_queues(bp->dev);

	/*
	 * Should not call netif_carrier_on since it will be called if the link
	 * is up when checking for link state
	 */
}


void bnx2x_panic_dump(struct bnx2x *bp, bool disable_int)
{
	int i;
	u16 j;
	struct hc_sp_status_block_data sp_sb_data;
	int func = BP_FUNC(bp);
#ifdef BNX2X_STOP_ON_ERROR
	u16 start = 0, end = 0;
	u8 cos;
#endif
	if (IS_PF(bp) && disable_int)
		bnx2x_int_disable(bp);

	bp->stats_state = STATS_STATE_DISABLED;
	bp->eth_stats.unrecoverable_error++;
	DP(BNX2X_MSG_STATS, "stats_state - DISABLED\n");

	BNX2X_ERR("begin crash dump -----------------\n");

	/* Indices */
	/* Common */
	if (IS_PF(bp)) {
		struct host_sp_status_block *def_sb = bp->def_status_blk;
		int data_size, cstorm_offset;

		BNX2X_ERR("def_idx(0x%x)  def_att_idx(0x%x)  attn_state(0x%x)  spq_prod_idx(0x%x) next_stats_cnt(0x%x)\n",
			  bp->def_idx, bp->def_att_idx, bp->attn_state,
			  bp->spq_prod_idx, bp->stats_counter);
		BNX2X_ERR("DSB: attn bits(0x%x)  ack(0x%x)  id(0x%x)  idx(0x%x)\n",
			  def_sb->atten_status_block.attn_bits,
			  def_sb->atten_status_block.attn_bits_ack,
			  def_sb->atten_status_block.status_block_id,
			  def_sb->atten_status_block.attn_bits_index);
		BNX2X_ERR("     def (");
		for (i = 0; i < HC_SP_SB_MAX_INDICES; i++)
			pr_cont("0x%x%s",
				def_sb->sp_sb.index_values[i],
				(i == HC_SP_SB_MAX_INDICES - 1) ? ")  " : " ");

		data_size = sizeof(struct hc_sp_status_block_data) /
			    sizeof(u32);
		cstorm_offset = CSTORM_SP_STATUS_BLOCK_DATA_OFFSET(func);
		for (i = 0; i < data_size; i++)
			*((u32 *)&sp_sb_data + i) =
				REG_RD(bp, BAR_CSTRORM_INTMEM + cstorm_offset +
					   i * sizeof(u32));

		pr_cont("igu_sb_id(0x%x)  igu_seg_id(0x%x) pf_id(0x%x)  vnic_id(0x%x)  vf_id(0x%x)  vf_valid (0x%x) state(0x%x)\n",
			sp_sb_data.igu_sb_id,
			sp_sb_data.igu_seg_id,
			sp_sb_data.p_func.pf_id,
			sp_sb_data.p_func.vnic_id,
			sp_sb_data.p_func.vf_id,
			sp_sb_data.p_func.vf_valid,
			sp_sb_data.state);
	}

	for_each_eth_queue(bp, i) {
		struct bnx2x_fastpath *fp = &bp->fp[i];
		int loop;
		struct hc_status_block_data_e2 sb_data_e2;
		struct hc_status_block_data_e1x sb_data_e1x;
		struct hc_status_block_sm  *hc_sm_p =
			CHIP_IS_E1x(bp) ?
			sb_data_e1x.common.state_machine :
			sb_data_e2.common.state_machine;
		struct hc_index_data *hc_index_p =
			CHIP_IS_E1x(bp) ?
			sb_data_e1x.index_data :
			sb_data_e2.index_data;
		u8 data_size, cos;
		u32 *sb_data_p;
		struct bnx2x_fp_txdata txdata;

		if (!bp->fp)
			break;

		if (!fp->rx_cons_sb)
			continue;

		/* Rx */
		BNX2X_ERR("fp%d: rx_bd_prod(0x%x)  rx_bd_cons(0x%x)  rx_comp_prod(0x%x)  rx_comp_cons(0x%x)  *rx_cons_sb(0x%x)\n",
			  i, fp->rx_bd_prod, fp->rx_bd_cons,
			  fp->rx_comp_prod,
			  fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
		BNX2X_ERR("     rx_sge_prod(0x%x)  last_max_sge(0x%x)  fp_hc_idx(0x%x)\n",
			  fp->rx_sge_prod, fp->last_max_sge,
			  le16_to_cpu(fp->fp_hc_idx));

		/* Tx */
		for_each_cos_in_tx_queue(fp, cos)
		{
			if (!fp->txdata_ptr[cos])
				break;

			txdata = *fp->txdata_ptr[cos];

			if (!txdata.tx_cons_sb)
				continue;

			BNX2X_ERR("fp%d: tx_pkt_prod(0x%x)  tx_pkt_cons(0x%x)  tx_bd_prod(0x%x)  tx_bd_cons(0x%x)  *tx_cons_sb(0x%x)\n",
				  i, txdata.tx_pkt_prod,
				  txdata.tx_pkt_cons, txdata.tx_bd_prod,
				  txdata.tx_bd_cons,
				  le16_to_cpu(*txdata.tx_cons_sb));
		}

		loop = CHIP_IS_E1x(bp) ?
			HC_SB_MAX_INDICES_E1X : HC_SB_MAX_INDICES_E2;

		/* host sb data */

		if (IS_FCOE_FP(fp))
			continue;

		BNX2X_ERR("     run indexes (");
		for (j = 0; j < HC_SB_MAX_SM; j++)
			pr_cont("0x%x%s",
			       fp->sb_running_index[j],
			       (j == HC_SB_MAX_SM - 1) ? ")" : " ");

		BNX2X_ERR("     indexes (");
		for (j = 0; j < loop; j++)
			pr_cont("0x%x%s",
			       fp->sb_index_values[j],
			       (j == loop - 1) ? ")" : " ");

		/* VF cannot access FW refelection for status block */
		if (IS_VF(bp))
			continue;

		/* fw sb data */
		data_size = CHIP_IS_E1x(bp) ?
			sizeof(struct hc_status_block_data_e1x) :
			sizeof(struct hc_status_block_data_e2);
		data_size /= sizeof(u32);
		sb_data_p = CHIP_IS_E1x(bp) ?
			(u32 *)&sb_data_e1x :
			(u32 *)&sb_data_e2;
		/* copy sb data in here */
		for (j = 0; j < data_size; j++)
			*(sb_data_p + j) = REG_RD(bp, BAR_CSTRORM_INTMEM +
				CSTORM_STATUS_BLOCK_DATA_OFFSET(fp->fw_sb_id) +
				j * sizeof(u32));

		if (!CHIP_IS_E1x(bp)) {
			pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) vnic_id(0x%x)  same_igu_sb_1b(0x%x) state(0x%x)\n",
				sb_data_e2.common.p_func.pf_id,
				sb_data_e2.common.p_func.vf_id,
				sb_data_e2.common.p_func.vf_valid,
				sb_data_e2.common.p_func.vnic_id,
				sb_data_e2.common.same_igu_sb_1b,
				sb_data_e2.common.state);
		} else {
			pr_cont("pf_id(0x%x)  vf_id(0x%x)  vf_valid(0x%x) vnic_id(0x%x)  same_igu_sb_1b(0x%x) state(0x%x)\n",
				sb_data_e1x.common.p_func.pf_id,
				sb_data_e1x.common.p_func.vf_id,
				sb_data_e1x.common.p_func.vf_valid,
				sb_data_e1x.common.p_func.vnic_id,
				sb_data_e1x.common.same_igu_sb_1b,
				sb_data_e1x.common.state);
		}

		/* SB_SMs data */
		for (j = 0; j < HC_SB_MAX_SM; j++) {
			pr_cont("SM[%d] __flags (0x%x) igu_sb_id (0x%x)  igu_seg_id(0x%x) time_to_expire (0x%x) timer_value(0x%x)\n",
				j, hc_sm_p[j].__flags,
				hc_sm_p[j].igu_sb_id,
				hc_sm_p[j].igu_seg_id,
				hc_sm_p[j].time_to_expire,
				hc_sm_p[j].timer_value);
		}

		/* Indices data */
		for (j = 0; j < loop; j++) {
			pr_cont("INDEX[%d] flags (0x%x) timeout (0x%x)\n", j,
			       hc_index_p[j].flags,
			       hc_index_p[j].timeout);
		}
	}

#ifdef BNX2X_STOP_ON_ERROR
	if (IS_PF(bp)) {
		/* event queue */
		BNX2X_ERR("eq cons %x prod %x\n", bp->eq_cons, bp->eq_prod);
		for (i = 0; i < NUM_EQ_DESC; i++) {
			u32 *data = (u32 *)&bp->eq_ring[i].message.data;

			BNX2X_ERR("event queue [%d]: header: opcode %d, error %d\n",
				  i, bp->eq_ring[i].message.opcode,
				  bp->eq_ring[i].message.error);
			BNX2X_ERR("data: %x %x %x\n",
				  data[0], data[1], data[2]);
		}
	}

	/* Rings */
	/* Rx */
	for_each_valid_rx_queue(bp, i) {
		struct bnx2x_fastpath *fp = &bp->fp[i];

		if (!bp->fp)
			break;

		if (!fp->rx_cons_sb)
			continue;

		start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
		end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
		for (j = start; j != end; j = RX_BD(j + 1)) {
			u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
			struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];

			BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
				  i, j, rx_bd[1], rx_bd[0], sw_bd->data);
		}

		start = RX_SGE(fp->rx_sge_prod);
		end = RX_SGE(fp->last_max_sge);
		for (j = start; j != end; j = RX_SGE(j + 1)) {
			u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
			struct sw_rx_page *sw_page = &fp->rx_page_ring[j];

			BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
				  i, j, rx_sge[1], rx_sge[0], sw_page->page);
		}

		start = RCQ_BD(fp->rx_comp_cons - 10);
		end = RCQ_BD(fp->rx_comp_cons + 503);
		for (j = start; j != end; j = RCQ_BD(j + 1)) {
			u32 *cqe = (u32 *)&fp->rx_comp_ring[j];

			BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
				  i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
		}
	}

	/* Tx */
	for_each_valid_tx_queue(bp, i) {
		struct bnx2x_fastpath *fp = &bp->fp[i];

		if (!bp->fp)
			break;

		for_each_cos_in_tx_queue(fp, cos) {
			struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos];

			if (!fp->txdata_ptr[cos])
				break;

			if (!txdata->tx_cons_sb)
				continue;

			start = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) - 10);
			end = TX_BD(le16_to_cpu(*txdata->tx_cons_sb) + 245);
			for (j = start; j != end; j = TX_BD(j + 1)) {
				struct sw_tx_bd *sw_bd =
					&txdata->tx_buf_ring[j];

				BNX2X_ERR("fp%d: txdata %d, packet[%x]=[%p,%x]\n",
					  i, cos, j, sw_bd->skb,
					  sw_bd->first_bd);
			}

			start = TX_BD(txdata->tx_bd_cons - 10);
			end = TX_BD(txdata->tx_bd_cons + 254);
			for (j = start; j != end; j = TX_BD(j + 1)) {
				u32 *tx_bd = (u32 *)&txdata->tx_desc_ring[j];

				BNX2X_ERR("fp%d: txdata %d, tx_bd[%x]=[%x:%x:%x:%x]\n",
					  i, cos, j, tx_bd[0], tx_bd[1],
					  tx_bd[2], tx_bd[3]);
			}
		}
	}
#endif
	if (IS_PF(bp)) {
		bnx2x_fw_dump(bp);
		bnx2x_mc_assert(bp);
	}
	BNX2X_ERR("end crash dump -----------------\n");
}


static void bnx2x_reset_mcp_prep(struct bnx2x *bp, u32 *magic_val)
{
	u32 shmem;
	u32 validity_offset;

	DP(NETIF_MSG_HW | NETIF_MSG_IFUP, "Starting\n");

	/* Set `magic' bit in order to save MF config */
	if (!CHIP_IS_E1(bp))
		bnx2x_clp_reset_prep(bp, magic_val);

	/* Get shmem offset */
	shmem = REG_RD(bp, MISC_REG_SHARED_MEM_ADDR);
	validity_offset =
		offsetof(struct shmem_region, validity_map[BP_PORT(bp)]);

	/* Clear validity map flags */
	if (shmem > 0)
		REG_WR(bp, shmem + validity_offset, 0);
}


void bnx2x_igu_clear_sb_gen(struct bnx2x *bp, u8 func, u8 idu_sb_id, bool is_pf)
{
	u32 data, ctl, cnt = 100;
	u32 igu_addr_data = IGU_REG_COMMAND_REG_32LSB_DATA;
	u32 igu_addr_ctl = IGU_REG_COMMAND_REG_CTRL;
	u32 igu_addr_ack = IGU_REG_CSTORM_TYPE_0_SB_CLEANUP + (idu_sb_id/32)*4;
	u32 sb_bit =  1 << (idu_sb_id%32);
	u32 func_encode = func | (is_pf ? 1 : 0) << IGU_FID_ENCODE_IS_PF_SHIFT;
	u32 addr_encode = IGU_CMD_E2_PROD_UPD_BASE + idu_sb_id;

	/* Not supported in BC mode */
	if (CHIP_INT_MODE_IS_BC(bp))
		return;

	data = (IGU_USE_REGISTER_cstorm_type_0_sb_cleanup
			<< IGU_REGULAR_CLEANUP_TYPE_SHIFT)	|
		IGU_REGULAR_CLEANUP_SET				|
		IGU_REGULAR_BCLEANUP;

	ctl = addr_encode << IGU_CTRL_REG_ADDRESS_SHIFT		|
	      func_encode << IGU_CTRL_REG_FID_SHIFT		|
	      IGU_CTRL_CMD_TYPE_WR << IGU_CTRL_REG_TYPE_SHIFT;

	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
			 data, igu_addr_data);
	REG_WR(bp, igu_addr_data, data);
	mmiowb();
	barrier();
	DP(NETIF_MSG_HW, "write 0x%08x to IGU(via GRC) addr 0x%x\n",
			  ctl, igu_addr_ctl);
	REG_WR(bp, igu_addr_ctl, ctl);
	mmiowb();
	barrier();

	/* wait for clean up to finish */
	while (!(REG_RD(bp, igu_addr_ack) & sb_bit) && --cnt)
		msleep(20);

	if (!(REG_RD(bp, igu_addr_ack) & sb_bit)) {
		DP(NETIF_MSG_HW,
		   "Unable to finish IGU cleanup: idu_sb_id %d offset %d bit %d (cnt %d)\n",
			  idu_sb_id, idu_sb_id/32, idu_sb_id%32, cnt);
	}
}


static void bnx2x_hw_enable_status(struct bnx2x *bp)
{
	u32 val;

	val = REG_RD(bp, CFC_REG_WEAK_ENABLE_PF);
	DP(BNX2X_MSG_SP, "CFC_REG_WEAK_ENABLE_PF is 0x%x\n", val);

	val = REG_RD(bp, PBF_REG_DISABLE_PF);
	DP(BNX2X_MSG_SP, "PBF_REG_DISABLE_PF is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSI_EN);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSI_EN is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_EN);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_EN is 0x%x\n", val);

	val = REG_RD(bp, IGU_REG_PCI_PF_MSIX_FUNC_MASK);
	DP(BNX2X_MSG_SP, "IGU_REG_PCI_PF_MSIX_FUNC_MASK is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_SHADOW_BME_PF_7_0_CLR is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_FLR_REQUEST_PF_7_0_CLR is 0x%x\n", val);

	val = REG_RD(bp, PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER);
	DP(BNX2X_MSG_SP, "PGLUE_B_REG_INTERNAL_PFID_ENABLE_MASTER is 0x%x\n",
	   val);
}


static void bnx2x_map_sb_state_machines(struct hc_index_data *index_data)
{
	/* zero out state machine indices */
	/* rx indices */
	index_data[HC_INDEX_ETH_RX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;

	/* tx indices */
	index_data[HC_INDEX_OOO_TX_CQ_CONS].flags &= ~HC_INDEX_DATA_SM_ID;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags &= ~HC_INDEX_DATA_SM_ID;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags &= ~HC_INDEX_DATA_SM_ID;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags &= ~HC_INDEX_DATA_SM_ID;

	/* map indices */
	/* rx indices */
	index_data[HC_INDEX_ETH_RX_CQ_CONS].flags |=
		SM_RX_ID << HC_INDEX_DATA_SM_ID_SHIFT;

	/* tx indices */
	index_data[HC_INDEX_OOO_TX_CQ_CONS].flags |=
		SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS0].flags |=
		SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS1].flags |=
		SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
	index_data[HC_INDEX_ETH_TX_CQ_CONS_COS2].flags |=
		SM_TX_ID << HC_INDEX_DATA_SM_ID_SHIFT;
}


static void bnx2x_write_dmae_phys_len(struct bnx2x *bp, dma_addr_t phys_addr,
				      u32 addr, u32 len)
{
	int dmae_wr_max = DMAE_LEN32_WR_MAX(bp);
	int offset = 0;

	while (len > dmae_wr_max) {
		bnx2x_write_dmae(bp, phys_addr + offset,
				 addr + offset, dmae_wr_max);
		offset += dmae_wr_max * 4;
		len -= dmae_wr_max;
	}

	bnx2x_write_dmae(bp, phys_addr + offset, addr + offset, len);
}


static int bnx2x_prev_unload_uncommon(struct bnx2x *bp)
{
	int rc;

	BNX2X_DEV_INFO("Uncommon unload Flow\n");

	/* Test if previous unload process was already finished for this path */
	if (bnx2x_prev_is_path_marked(bp))
		return bnx2x_prev_mcp_done(bp);

	BNX2X_DEV_INFO("Path is unmarked\n");

	/* Cannot proceed with FLR if UNDI is loaded, since FW does not match */
	if (bnx2x_prev_is_after_undi(bp))
		goto out;

	/* If function has FLR capabilities, and existing FW version matches
	 * the one required, then FLR will be sufficient to clean any residue
	 * left by previous driver
	 */
	rc = bnx2x_compare_fw_ver(bp, FW_MSG_CODE_DRV_LOAD_FUNCTION, false);

	if (!rc) {
		/* fw version is good */
		BNX2X_DEV_INFO("FW version matches our own. Attempting FLR\n");
		rc = bnx2x_do_flr(bp);
	}

	if (!rc) {
		/* FLR was performed */
		BNX2X_DEV_INFO("FLR successful\n");
		return 0;
	}

	BNX2X_DEV_INFO("Could not FLR\n");

out:
	/* Close the MCP request, return failure*/
	rc = bnx2x_prev_mcp_done(bp);
	if (!rc)
		rc = BNX2X_PREV_WAIT_NEEDED;

	return rc;
}


static void bnx2x_update_coalesce_sb(struct bnx2x *bp, u8 fw_sb_id,
				     u16 tx_usec, u16 rx_usec)
{
	bnx2x_update_coalesce_sb_index(bp, fw_sb_id, HC_INDEX_ETH_RX_CQ_CONS,
				    false, rx_usec);
	bnx2x_update_coalesce_sb_index(bp, fw_sb_id,
				       HC_INDEX_ETH_TX_CQ_CONS_COS0, false,
				       tx_usec);
	bnx2x_update_coalesce_sb_index(bp, fw_sb_id,
				       HC_INDEX_ETH_TX_CQ_CONS_COS1, false,
				       tx_usec);
	bnx2x_update_coalesce_sb_index(bp, fw_sb_id,
				       HC_INDEX_ETH_TX_CQ_CONS_COS2, false,
				       tx_usec);
}