static int do_con_write(struct tty_struct *tty, const unsigned char *buf, int count)
{
	int c, next_c, tc, ok, n = 0, draw_x = -1;
	unsigned int currcons;
	unsigned long draw_from = 0, draw_to = 0;
	struct vc_data *vc;
	unsigned char vc_attr;
	struct vt_notifier_param param;
	uint8_t rescan;
	uint8_t inverse;
	uint8_t width;
	u16 himask, charmask;

	if (in_interrupt())
		return count;

	console_lock();
	vc = tty->driver_data;
	if (vc == NULL) {
		pr_err("vt: argh, driver_data is NULL !\n");
		console_unlock();
		return 0;
	}

	currcons = vc->vc_num;
	if (!vc_cons_allocated(currcons)) {
		/* could this happen? */
		pr_warn_once("con_write: tty %d not allocated\n", currcons+1);
		console_unlock();
		return 0;
	}

	himask = vc->vc_hi_font_mask;
	charmask = himask ? 0x1ff : 0xff;

	/* undraw cursor first */
	if (con_is_fg(vc))
		hide_cursor(vc);

	param.vc = vc;

	while (!tty->stopped && count) {
		int orig = *buf;
		c = orig;
		buf++;
		n++;
		count--;
		rescan = 0;
		inverse = 0;
		width = 1;

		/* Do no translation at all in control states */
		if (vc->vc_state != ESnormal) {
			tc = c;
		} else if (vc->vc_utf && !vc->vc_disp_ctrl) {
		    /* Combine UTF-8 into Unicode in vc_utf_char.
		     * vc_utf_count is the number of continuation bytes still
		     * expected to arrive.
		     * vc_npar is the number of continuation bytes arrived so
		     * far
		     */
rescan_last_byte:
		    if ((c & 0xc0) == 0x80) {
			/* Continuation byte received */
			static const uint32_t utf8_length_changes[] = { 0x0000007f, 0x000007ff, 0x0000ffff, 0x001fffff, 0x03ffffff, 0x7fffffff };
			if (vc->vc_utf_count) {
			    vc->vc_utf_char = (vc->vc_utf_char << 6) | (c & 0x3f);
			    vc->vc_npar++;
			    if (--vc->vc_utf_count) {
				/* Still need some bytes */
				continue;
			    }
			    /* Got a whole character */
			    c = vc->vc_utf_char;
			    /* Reject overlong sequences */
			    if (c <= utf8_length_changes[vc->vc_npar - 1] ||
					c > utf8_length_changes[vc->vc_npar])
				c = 0xfffd;
			} else {
			    /* Unexpected continuation byte */
			    vc->vc_utf_count = 0;
			    c = 0xfffd;
			}
		    } else {
			/* Single ASCII byte or first byte of a sequence received */
			if (vc->vc_utf_count) {
			    /* Continuation byte expected */
			    rescan = 1;
			    vc->vc_utf_count = 0;
			    c = 0xfffd;
			} else if (c > 0x7f) {
			    /* First byte of a multibyte sequence received */
			    vc->vc_npar = 0;
			    if ((c & 0xe0) == 0xc0) {
				vc->vc_utf_count = 1;
				vc->vc_utf_char = (c & 0x1f);
			    } else if ((c & 0xf0) == 0xe0) {
				vc->vc_utf_count = 2;
				vc->vc_utf_char = (c & 0x0f);
			    } else if ((c & 0xf8) == 0xf0) {
				vc->vc_utf_count = 3;
				vc->vc_utf_char = (c & 0x07);
			    } else if ((c & 0xfc) == 0xf8) {
				vc->vc_utf_count = 4;
				vc->vc_utf_char = (c & 0x03);
			    } else if ((c & 0xfe) == 0xfc) {
				vc->vc_utf_count = 5;
				vc->vc_utf_char = (c & 0x01);
			    } else {
				/* 254 and 255 are invalid */
				c = 0xfffd;
			    }
			    if (vc->vc_utf_count) {
				/* Still need some bytes */
				continue;
			    }
			}
			/* Nothing to do if an ASCII byte was received */
		    }
		    /* End of UTF-8 decoding. */
		    /* c is the received character, or U+FFFD for invalid sequences. */
		    /* Replace invalid Unicode code points with U+FFFD too */
		    if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff)
			c = 0xfffd;
		    tc = c;
		} else {	/* no utf or alternate charset mode */
		    tc = vc_translate(vc, c);
		}

		param.c = tc;
		if (atomic_notifier_call_chain(&vt_notifier_list, VT_PREWRITE,
					&param) == NOTIFY_STOP)
			continue;

                /* If the original code was a control character we
                 * only allow a glyph to be displayed if the code is
                 * not normally used (such as for cursor movement) or
                 * if the disp_ctrl mode has been explicitly enabled.
                 * Certain characters (as given by the CTRL_ALWAYS
                 * bitmap) are always displayed as control characters,
                 * as the console would be pretty useless without
                 * them; to display an arbitrary font position use the
                 * direct-to-font zone in UTF-8 mode.
                 */
                ok = tc && (c >= 32 ||
			    !(vc->vc_disp_ctrl ? (CTRL_ALWAYS >> c) & 1 :
				  vc->vc_utf || ((CTRL_ACTION >> c) & 1)))
			&& (c != 127 || vc->vc_disp_ctrl)
			&& (c != 128+27);

		if (vc->vc_state == ESnormal && ok) {
			if (vc->vc_utf && !vc->vc_disp_ctrl) {
				if (is_double_width(c))
					width = 2;
			}
			/* Now try to find out how to display it */
			tc = conv_uni_to_pc(vc, tc);
			if (tc & ~charmask) {
				if (tc == -1 || tc == -2) {
				    continue; /* nothing to display */
				}
				/* Glyph not found */
				if ((!(vc->vc_utf && !vc->vc_disp_ctrl) || c < 128) && !(c & ~charmask)) {
				    /* In legacy mode use the glyph we get by a 1:1 mapping.
				       This would make absolutely no sense with Unicode in mind,
				       but do this for ASCII characters since a font may lack
				       Unicode mapping info and we don't want to end up with
				       having question marks only. */
				    tc = c;
				} else {
				    /* Display U+FFFD. If it's not found, display an inverse question mark. */
				    tc = conv_uni_to_pc(vc, 0xfffd);
				    if (tc < 0) {
					inverse = 1;
					tc = conv_uni_to_pc(vc, '?');
					if (tc < 0) tc = '?';
				    }
				}
			}

			if (!inverse) {
				vc_attr = vc->vc_attr;
			} else {
				/* invert vc_attr */
				if (!vc->vc_can_do_color) {
					vc_attr = (vc->vc_attr) ^ 0x08;
				} else if (vc->vc_hi_font_mask == 0x100) {
					vc_attr = ((vc->vc_attr) & 0x11) | (((vc->vc_attr) & 0xe0) >> 4) | (((vc->vc_attr) & 0x0e) << 4);
				} else {
					vc_attr = ((vc->vc_attr) & 0x88) | (((vc->vc_attr) & 0x70) >> 4) | (((vc->vc_attr) & 0x07) << 4);
				}
				con_flush(vc, draw_from, draw_to, &draw_x);
			}

			next_c = c;
			while (1) {
				if (vc->vc_need_wrap || vc->vc_decim)
					con_flush(vc, draw_from, draw_to,
							&draw_x);
				if (vc->vc_need_wrap) {
					cr(vc);
					lf(vc);
				}
				if (vc->vc_decim)
					insert_char(vc, 1);
				vc_uniscr_putc(vc, next_c);
				scr_writew(himask ?
					     ((vc_attr << 8) & ~himask) + ((tc & 0x100) ? himask : 0) + (tc & 0xff) :
					     (vc_attr << 8) + tc,
					   (u16 *) vc->vc_pos);
				if (con_should_update(vc) && draw_x < 0) {
					draw_x = vc->vc_x;
					draw_from = vc->vc_pos;
				}
				if (vc->vc_x == vc->vc_cols - 1) {
					vc->vc_need_wrap = vc->vc_decawm;
					draw_to = vc->vc_pos + 2;
				} else {
					vc->vc_x++;
					draw_to = (vc->vc_pos += 2);
				}

				if (!--width) break;

				tc = conv_uni_to_pc(vc, ' '); /* A space is printed in the second column */
				if (tc < 0) tc = ' ';
				next_c = ' ';
			}
			notify_write(vc, c);

			if (inverse)
				con_flush(vc, draw_from, draw_to, &draw_x);

			if (rescan) {
				rescan = 0;
				inverse = 0;
				width = 1;
				c = orig;
				goto rescan_last_byte;
			}
			continue;
		}
		con_flush(vc, draw_from, draw_to, &draw_x);
		do_con_trol(tty, vc, orig);
	}
	con_flush(vc, draw_from, draw_to, &draw_x);
	vc_uniscr_debug_check(vc);
	console_conditional_schedule();
	notify_update(vc);
	console_unlock();
	return n;
}


void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
{
	unsigned short *p;

	WARN_CONSOLE_UNLOCKED();

	count /= 2;
	p = screenpos(vc, offset, viewed);
	if (vc->vc_sw->con_invert_region) {
		vc->vc_sw->con_invert_region(vc, p, count);
	} else {
		u16 *q = p;
		int cnt = count;
		u16 a;

		if (!vc->vc_can_do_color) {
			while (cnt--) {
			    a = scr_readw(q);
			    a ^= 0x0800;
			    scr_writew(a, q);
			    q++;
			}
		} else if (vc->vc_hi_font_mask == 0x100) {
			while (cnt--) {
				a = scr_readw(q);
				a = ((a) & 0x11ff) | (((a) & 0xe000) >> 4) | (((a) & 0x0e00) << 4);
				scr_writew(a, q);
				q++;
			}
		} else {
			while (cnt--) {
				a = scr_readw(q);
				a = ((a) & 0x88ff) | (((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4);
				scr_writew(a, q);
				q++;
			}
		}
	}

	if (con_should_update(vc))
		do_update_region(vc, (unsigned long) p, count);
	notify_update(vc);
}


htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
	                 const char *encoding) {
    htmlNodeDumpFormatOutput(buf, cur, (xmlNodePtr) cur, encoding, 1);
}


htmlIsBooleanAttr(const xmlChar *name)
{
    int i = 0;

    while (htmlBooleanAttrs[i] != NULL) {
        if (xmlStrcasecmp((const xmlChar *)htmlBooleanAttrs[i], name) == 0)
            return 1;
        i++;
    }
    return 0;
}


htmlBufNodeDumpFormat(xmlBufPtr buf, xmlDocPtr doc, xmlNodePtr cur,
	           int format) {
    size_t use;
    int ret;
    xmlOutputBufferPtr outbuf;

    if (cur == NULL) {
	return (-1);
    }
    if (buf == NULL) {
	return (-1);
    }
    outbuf = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
    if (outbuf == NULL) {
        htmlSaveErrMemory("allocating HTML output buffer");
	return (-1);
    }
    memset(outbuf, 0, (size_t) sizeof(xmlOutputBuffer));
    outbuf->buffer = buf;
    outbuf->encoder = NULL;
    outbuf->writecallback = NULL;
    outbuf->closecallback = NULL;
    outbuf->context = NULL;
    outbuf->written = 0;

    use = xmlBufUse(buf);
    htmlNodeDumpFormatOutput(outbuf, doc, cur, NULL, format);
    xmlFree(outbuf);
    ret = xmlBufUse(buf) - use;
    return (ret);
}


static void igmp_ifc_event(struct in_device *in_dev)
{
	struct net *net = dev_net(in_dev->dev);
	if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev))
		return;
	in_dev->mr_ifc_count = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
	igmp_ifc_start_timer(in_dev, 1);
}


static void igmpv3_send_cr(struct in_device *in_dev)
{
	struct ip_mc_list *pmc, *pmc_prev, *pmc_next;
	struct sk_buff *skb = NULL;
	int type, dtype;

	rcu_read_lock();
	spin_lock_bh(&in_dev->mc_tomb_lock);

	/* deleted MCA's */
	pmc_prev = NULL;
	for (pmc = in_dev->mc_tomb; pmc; pmc = pmc_next) {
		pmc_next = pmc->next;
		if (pmc->sfmode == MCAST_INCLUDE) {
			type = IGMPV3_BLOCK_OLD_SOURCES;
			dtype = IGMPV3_BLOCK_OLD_SOURCES;
			skb = add_grec(skb, pmc, type, 1, 0);
			skb = add_grec(skb, pmc, dtype, 1, 1);
		}
		if (pmc->crcount) {
			if (pmc->sfmode == MCAST_EXCLUDE) {
				type = IGMPV3_CHANGE_TO_INCLUDE;
				skb = add_grec(skb, pmc, type, 1, 0);
			}
			pmc->crcount--;
			if (pmc->crcount == 0) {
				igmpv3_clear_zeros(&pmc->tomb);
				igmpv3_clear_zeros(&pmc->sources);
			}
		}
		if (pmc->crcount == 0 && !pmc->tomb && !pmc->sources) {
			if (pmc_prev)
				pmc_prev->next = pmc_next;
			else
				in_dev->mc_tomb = pmc_next;
			in_dev_put(pmc->interface);
			kfree_pmc(pmc);
		} else
			pmc_prev = pmc;
	}
	spin_unlock_bh(&in_dev->mc_tomb_lock);

	/* change recs */
	for_each_pmc_rcu(in_dev, pmc) {
		spin_lock_bh(&pmc->lock);
		if (pmc->sfcount[MCAST_EXCLUDE]) {
			type = IGMPV3_BLOCK_OLD_SOURCES;
			dtype = IGMPV3_ALLOW_NEW_SOURCES;
		} else {
			type = IGMPV3_ALLOW_NEW_SOURCES;
			dtype = IGMPV3_BLOCK_OLD_SOURCES;
		}
		skb = add_grec(skb, pmc, type, 0, 0);
		skb = add_grec(skb, pmc, dtype, 0, 1);	/* deleted sources */

		/* filter mode changes */
		if (pmc->crcount) {
			if (pmc->sfmode == MCAST_EXCLUDE)
				type = IGMPV3_CHANGE_TO_EXCLUDE;
			else
				type = IGMPV3_CHANGE_TO_INCLUDE;
			skb = add_grec(skb, pmc, type, 0, 0);
			pmc->crcount--;
		}
		spin_unlock_bh(&pmc->lock);
	}
	rcu_read_unlock();

	if (!skb)
		return;
	(void) igmpv3_sendpack(skb);
}


void ip_mc_up(struct in_device *in_dev)
{
	struct ip_mc_list *pmc;

	ASSERT_RTNL();

	ip_mc_reset(in_dev);
	ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);

	for_each_pmc_rtnl(in_dev, pmc) {
#ifdef CONFIG_IP_MULTICAST
		igmpv3_del_delrec(in_dev, pmc);
#endif
		igmp_group_added(pmc);
	}
}


static void igmp_gq_start_timer(struct in_device *in_dev)
{
	int tv = prandom_u32() % in_dev->mr_maxdelay;
	unsigned long exp = jiffies + tv + 2;

	if (in_dev->mr_gq_running &&
	    time_after_eq(exp, (in_dev->mr_gq_timer).expires))
		return;

	in_dev->mr_gq_running = 1;
	if (!mod_timer(&in_dev->mr_gq_timer, exp))
		in_dev_hold(in_dev);
}


int __init igmp_mc_init(void)
{
#if defined(CONFIG_PROC_FS)
	int err;

	err = register_pernet_subsys(&igmp_net_ops);
	if (err)
		return err;
	err = register_netdevice_notifier(&igmp_notifier);
	if (err)
		goto reg_notif_fail;
	return 0;

reg_notif_fail:
	unregister_pernet_subsys(&igmp_net_ops);
	return err;
#else
	return register_netdevice_notifier(&igmp_notifier);
#endif
}


igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted)
{
	struct ip_sf_list *psf;
	int scount = 0;

	for (psf = pmc->sources; psf; psf = psf->sf_next) {
		if (!is_in(pmc, psf, type, gdeleted, sdeleted))
			continue;
		scount++;
	}
	return scount;
}


static void igmp_ifc_timer_expire(struct timer_list *t)
{
	struct in_device *in_dev = from_timer(in_dev, t, mr_ifc_timer);

	igmpv3_send_cr(in_dev);
	if (in_dev->mr_ifc_count) {
		in_dev->mr_ifc_count--;
		igmp_ifc_start_timer(in_dev,
				     unsolicited_report_interval(in_dev));
	}
	in_dev_put(in_dev);
}


static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
{
	struct ip_mc_list *pmc, *pmc_prev;
	struct ip_sf_list *psf;
	struct net *net = dev_net(in_dev->dev);
	__be32 multiaddr = im->multiaddr;

	spin_lock_bh(&in_dev->mc_tomb_lock);
	pmc_prev = NULL;
	for (pmc = in_dev->mc_tomb; pmc; pmc = pmc->next) {
		if (pmc->multiaddr == multiaddr)
			break;
		pmc_prev = pmc;
	}
	if (pmc) {
		if (pmc_prev)
			pmc_prev->next = pmc->next;
		else
			in_dev->mc_tomb = pmc->next;
	}
	spin_unlock_bh(&in_dev->mc_tomb_lock);

	spin_lock_bh(&im->lock);
	if (pmc) {
		im->interface = pmc->interface;
		if (im->sfmode == MCAST_INCLUDE) {
			swap(im->tomb, pmc->tomb);
			swap(im->sources, pmc->sources);
			for (psf = im->sources; psf; psf = psf->sf_next)
				psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
		} else {
			im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
		}
		in_dev_put(pmc->interface);
		kfree_pmc(pmc);
	}
	spin_unlock_bh(&im->lock);
}


static bool igmp_heard_report(struct in_device *in_dev, __be32 group)
{
	struct ip_mc_list *im;
	struct net *net = dev_net(in_dev->dev);

	/* Timers are only set for non-local groups */

	if (group == IGMP_ALL_HOSTS)
		return false;
	if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports)
		return false;

	rcu_read_lock();
	for_each_pmc_rcu(in_dev, im) {
		if (im->multiaddr == group) {
			igmp_stop_timer(im);
			break;
		}
	}
	rcu_read_unlock();
	return false;
}


static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
			      unsigned int mode)
{
	__be32 addr = imr->imr_multiaddr.s_addr;
	struct ip_mc_socklist *iml, *i;
	struct in_device *in_dev;
	struct inet_sock *inet = inet_sk(sk);
	struct net *net = sock_net(sk);
	int ifindex;
	int count = 0;
	int err;

	ASSERT_RTNL();

	if (!ipv4_is_multicast(addr))
		return -EINVAL;

	in_dev = ip_mc_find_dev(net, imr);

	if (!in_dev) {
		err = -ENODEV;
		goto done;
	}

	err = -EADDRINUSE;
	ifindex = imr->imr_ifindex;
	for_each_pmc_rtnl(inet, i) {
		if (i->multi.imr_multiaddr.s_addr == addr &&
		    i->multi.imr_ifindex == ifindex)
			goto done;
		count++;
	}
	err = -ENOBUFS;
	if (count >= net->ipv4.sysctl_igmp_max_memberships)
		goto done;
	iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
	if (!iml)
		goto done;

	memcpy(&iml->multi, imr, sizeof(*imr));
	iml->next_rcu = inet->mc_list;
	iml->sflist = NULL;
	iml->sfmode = mode;
	rcu_assign_pointer(inet->mc_list, iml);
	____ip_mc_inc_group(in_dev, addr, mode, GFP_KERNEL);
	err = 0;
done:
	return err;
}


static irqreturn_t xen_arm_callback(int irq, void *arg)
{
	xen_hvm_evtchn_do_upcall();
	return IRQ_HANDLED;
}


static void xen_read_wallclock(struct timespec64 *ts)
{
	u32 version;
	struct timespec64 now, ts_monotonic;
	struct shared_info *s = HYPERVISOR_shared_info;
	struct pvclock_wall_clock *wall_clock = &(s->wc);

	/* get wallclock at system boot */
	do {
		version = wall_clock->version;
		rmb();		/* fetch version before time */
		now.tv_sec  = ((uint64_t)wall_clock->sec_hi << 32) | wall_clock->sec;
		now.tv_nsec = wall_clock->nsec;
		rmb();		/* fetch time before checking version */
	} while ((wall_clock->version & 1) || (version != wall_clock->version));

	/* time since system boot */
	ktime_get_ts64(&ts_monotonic);
	*ts = timespec64_add(now, ts_monotonic);
}


static int xen_starting_cpu(unsigned int cpu)
{
	struct vcpu_register_vcpu_info info;
	struct vcpu_info *vcpup;
	int err;

	/*
	 * VCPUOP_register_vcpu_info cannot be called twice for the same
	 * vcpu, so if vcpu_info is already registered, just get out. This
	 * can happen with cpu-hotplug.
	 */
	if (per_cpu(xen_vcpu, cpu) != NULL)
		goto after_register_vcpu_info;

	pr_info("Xen: initializing cpu%d\n", cpu);
	vcpup = per_cpu_ptr(xen_vcpu_info, cpu);

	info.mfn = percpu_to_gfn(vcpup);
	info.offset = xen_offset_in_page(vcpup);

	err = HYPERVISOR_vcpu_op(VCPUOP_register_vcpu_info, xen_vcpu_nr(cpu),
				 &info);
	BUG_ON(err);
	per_cpu(xen_vcpu, cpu) = vcpup;

	if (!xen_kernel_unmapped_at_usr())
		xen_setup_runstate_info(cpu);

after_register_vcpu_info:
	enable_percpu_irq(xen_events_irq, 0);
	return 0;
}


static MagickBooleanType ReadTIM2ImageData(const ImageInfo *image_info,
  Image *image,TIM2ImageHeader *header,char clut_depth,char bits_per_pixel,
  ExceptionInfo *exception)
{
  MagickBooleanType
    status;

  ssize_t
    x;

  Quantum
    *q;

  unsigned char
    *p;

  size_t
    bits_per_line,
    bytes_per_line;

  ssize_t
    count,
    y;

  unsigned char
    *row_data;

  unsigned int
    word;

  status=SetImageExtent(image,image->columns,image->rows,exception);
  if (status == MagickFalse)
    return(MagickFalse);
  /*
   * User data
   */
  status=DiscardBlobBytes(image,header->header_size-48);
  if (status == MagickFalse)
    return(MagickFalse);
  /*
   * Image data
   */
  bits_per_line=image->columns*bits_per_pixel;
  bytes_per_line=bits_per_line/8 + ((bits_per_line%8==0) ? 0 : 1);
  row_data=(unsigned char*) AcquireQuantumMemory(1,bytes_per_line);
  if (row_data == (unsigned char *) NULL)
    ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
      image_info->filename);
  if (clut_depth != 0)
    {
      image->colors=header->clut_color_count;
      if (AcquireImageColormap(image,image->colors,exception) == MagickFalse)
        {
          row_data=(unsigned char *) RelinquishMagickMemory(row_data);
          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
            image_info->filename);
        }
      switch (bits_per_pixel)
      {
        case 4:
        {
          for (y=0; y<(ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            count=ReadBlob(image,bytes_per_line,row_data);
            if (count != (ssize_t) bytes_per_line)
              {
                row_data=(unsigned char *) RelinquishMagickMemory(row_data);
                ThrowBinaryException(CorruptImageError,
                  "InsufficientImageDataInFile",image_info->filename);
              }
            p=row_data;
            for (x=0; x < ((ssize_t) image->columns-1); x+=2)
            {
              SetPixelIndex(image,(*p >> 0) & 0x0F,q);
              q+=GetPixelChannels(image);
              SetPixelIndex(image,(*p >> 4) & 0x0F,q);
              p++;
              q+=GetPixelChannels(image);
            }
            if ((image->columns % 2) != 0)
              {
                SetPixelIndex(image,(*p >> 4) & 0x0F,q);
                p++;
                q+=GetPixelChannels(image);
              }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,
                  (MagickOffsetType) y,image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
          break;
        }
        case 8:
        {
          for (y=0;y<(ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            count=ReadBlob(image,bytes_per_line,row_data);
            if (count != (ssize_t) bytes_per_line)
              {
                row_data=(unsigned char *) RelinquishMagickMemory(row_data);
                ThrowBinaryException(CorruptImageError,
                  "InsufficientImageDataInFile",image_info->filename);
              }
            p=row_data;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              SetPixelIndex(image,*p,q);
              p++;
              q+=GetPixelChannels(image);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,
                  (MagickOffsetType) y,image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
          break;
        }
        default:
        {
          row_data=(unsigned char *) RelinquishMagickMemory(row_data);
          ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
            image_info->filename);
        }
      }
    }
  else  /* has_clut==false */
    {
      switch (bits_per_pixel)
      {
        case 16:
        {
          for (y=0; y<(ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            count=ReadBlob(image,bytes_per_line,row_data);
            if (count != (ssize_t) bytes_per_line)
              {
                row_data=(unsigned char *) RelinquishMagickMemory(row_data);
                ThrowBinaryException(CorruptImageError,
                  "InsufficientImageDataInFile",image_info->filename);
              }
            p=row_data;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              word = ((unsigned int)* p   )<<0*8 |
                      ((unsigned int)*(p+1))<<1*8;

              SetPixelRed(image,GetChannelValue(word,0,RGBA16),q);
              SetPixelGreen(image,GetChannelValue(word,1,RGBA16),q);
              SetPixelBlue(image,GetChannelValue(word,2,RGBA16),q);
              SetPixelAlpha(image,GetAlpha(word,RGBA16),q);
              q+=GetPixelChannels(image);
              p+=sizeof(unsigned short);
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,
                  (MagickOffsetType) y,image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
          break;
        }
        case 24:
        {
          for (y = 0; y<(ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            count=ReadBlob(image,bytes_per_line,row_data);
            if (count != (ssize_t) bytes_per_line)
              {
                row_data=(unsigned char *) RelinquishMagickMemory(row_data);
                ThrowBinaryException(CorruptImageError,
                  "InsufficientImageDataInFile",image_info->filename);
              }
            p=row_data;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              word = (unsigned int)(* p   )<<0*8 |
                      (unsigned int)(*(p+1))<<1*8 |
                      (unsigned int)(*(p+2))<<2*8;

              SetPixelRed(image,GetChannelValue(word,0,RGB24),q);
              SetPixelGreen(image,GetChannelValue(word,1,RGB24),q);
              SetPixelBlue(image,GetChannelValue(word,2,RGB24),q);
              q+=GetPixelChannels(image);
              p+=3;
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,
                  (MagickOffsetType) y,image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
          break;
        }
        case 32:
        {
          for (y = 0; y<(ssize_t) image->rows; y++)
          {
            q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);
            if (q == (Quantum *) NULL)
              break;
            count=ReadBlob(image,bytes_per_line,row_data);
            if (count != (ssize_t) bytes_per_line)
              {
                row_data=(unsigned char *) RelinquishMagickMemory(row_data);
                ThrowBinaryException(CorruptImageError,
                  "InsufficientImageDataInFile",image_info->filename);
              }
            p=row_data;
            for (x=0; x < (ssize_t) image->columns; x++)
            {
              word = ((unsigned int)* p   )<<0*8 |
                      ((unsigned int)*(p+1))<<1*8 |
                      ((unsigned int)*(p+2))<<2*8 |
                      ((unsigned int)*(p+3))<<3*8;

              SetPixelRed(image,GetChannelValue(word,0,RGBA32),q);
              SetPixelGreen(image,GetChannelValue(word,1,RGBA32),q);
              SetPixelBlue(image,GetChannelValue(word,2,RGBA32),q);
              SetPixelAlpha(image,GetAlpha(word,RGBA32),q);
              q+=GetPixelChannels(image);
              p+=4;
            }
            if (SyncAuthenticPixels(image,exception) == MagickFalse)
              break;
            if (image->previous == (Image *) NULL)
              {
                status=SetImageProgress(image,LoadImageTag,
                  (MagickOffsetType) y,image->rows);
                if (status == MagickFalse)
                  break;
              }
          }
          break;
        }
        default:
        {
          row_data=(unsigned char *) RelinquishMagickMemory(row_data);
          ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
            image_info->filename);
        }
      }
    }
  row_data=(unsigned char *) RelinquishMagickMemory(row_data);
  if ((status != MagickFalse) && (clut_depth != 0))
  {
    CSM
      csm;

    ssize_t
      i;

    unsigned char
      *clut_data;

    /*
      * ### Read CLUT Data ###
      */
    clut_data=(unsigned char *) AcquireQuantumMemory(1,header->clut_size);
    if (clut_data == (unsigned char *) NULL)
      ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
        image_info->filename);
    count=ReadBlob(image,header->clut_size,clut_data);
    if (count != (ssize_t) (header->clut_size))
      {
        clut_data=(unsigned char *) RelinquishMagickMemory(clut_data);
        ThrowBinaryException(CorruptImageError,"InsufficientImageDataInFile",
          image_info->filename);
      }
    /*
      * ### Process CLUT Data ###
      */
    p=clut_data;
    switch(clut_depth)
    {
      case 16:
      {
        for (i=0; i < (ssize_t) image->colors; i++)
        {
          word = ((unsigned short)* p   )<<0*8 |
                  ((unsigned short)*(p+1))<<1*8;

          image->colormap[i].red=GetChannelValue(word,0,RGBA16);
          image->colormap[i].green=GetChannelValue(word,1,RGBA16);
          image->colormap[i].blue=GetChannelValue(word,2,RGBA16);
          image->colormap[i].alpha=GetAlpha(word,RGBA16);
          p+=2;
        }
        break;
      }
      case 24:
      {
        for (i=0; i < (ssize_t) image->colors; i++)
        {
          word = ((unsigned int)* p   )<<0*8 |
                  ((unsigned int)*(p+1))<<1*8 |
                  ((unsigned int)*(p+2))<<2*8;

          image->colormap[i].red=GetChannelValue(word,0,RGB24);
          image->colormap[i].green=GetChannelValue(word,1,RGB24);
          image->colormap[i].blue=GetChannelValue(word,2,RGB24);
          p+=3;
        }
        break;
      }
      case 32:
      {
        for (i=0; i < (ssize_t) image->colors; i++)
        {
          word = ((unsigned int)* p   )<<0*8 |
                  ((unsigned int)*(p+1))<<1*8 |
                  ((unsigned int)*(p+2))<<2*8 |
                  ((unsigned int)*(p+3))<<3*8;

          image->colormap[i].red=GetChannelValue(word,0,RGBA32);
          image->colormap[i].green=GetChannelValue(word,1,RGBA32);
          image->colormap[i].blue=GetChannelValue(word,2,RGBA32);
          image->colormap[i].alpha=GetAlpha(word,RGBA32);
          p+=4;
        }
        break;
      }
    }
    clut_data=(unsigned char *) RelinquishMagickMemory(clut_data);
    /* CSM: CLUT Storage Mode */
    switch ((int) header->clut_type>>4)  /* High 4 bits */
    {
      case 0:
        csm=CSM1;
        break;
      case 1:
        csm=CSM2;
        break;
      default:
        ThrowBinaryException(CorruptImageError,"ImproperImageHeader",
          image_info->filename);
        break;
    }
    if (csm == CSM1)
      {
        PixelInfo
          *oldColormap;

        oldColormap=(PixelInfo *) AcquireQuantumMemory((size_t)(image->colors)+
          1,sizeof(*image->colormap));
        if (oldColormap == (PixelInfo *) NULL)
          ThrowBinaryException(ResourceLimitError,"MemoryAllocationFailed",
            image_info->filename);
        deshufflePalette(image,oldColormap);
        RelinquishMagickMemory(oldColormap);
      }
  }
  return(status);
}


int ZEXPORT inflateUndermine(strm, subvert)
z_streamp strm;
int subvert;
{
    struct inflate_state FAR *state;

    if (inflateStateCheck(strm)) return Z_STREAM_ERROR;
    state = (struct inflate_state FAR *)strm->state;
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
    state->sane = !subvert;
    return Z_OK;
#else
    (void)subvert;
    state->sane = 1;
    return Z_DATA_ERROR;
#endif
}


ipv4_to_ptr(uint32_t ipv4, char ptr[], size_t nm_len)
{
    static const char IPV4_PTR_SUFFIX[] = "\07in-addr\04arpa";
    int i;
    char* c = ptr;
    log_assert(nm_len == MAX_PTR_QNAME_IPV4); (void)nm_len;

    for (i = 0; i < 4; ++i) {
        *c = uitoa((unsigned int)(ipv4 % 256), c + 1);
        c += *c + 1;
	log_assert(c < ptr+nm_len);
        ipv4 /= 256;
    }

    log_assert(c + sizeof(IPV4_PTR_SUFFIX) <= ptr+nm_len);
    memmove(c, IPV4_PTR_SUFFIX, sizeof(IPV4_PTR_SUFFIX));

    return c + sizeof(IPV4_PTR_SUFFIX) - ptr;
}


void iter_store_parentside_neg(struct module_env* env,
        struct query_info* qinfo, struct reply_info* rep)
{
	/* TTL: NS from referral in iq->deleg_msg,
	 *      or first RR from iq->response,
	 *      or servfail5secs if !iq->response */
	time_t ttl = NORR_TTL;
	struct ub_packed_rrset_key* neg;
	struct packed_rrset_data* newd;
	if(rep) {
		struct ub_packed_rrset_key* rrset = reply_get_NS_rrset(rep);
		if(!rrset && rep->rrset_count != 0) rrset = rep->rrsets[0];
		if(rrset) ttl = ub_packed_rrset_ttl(rrset);
	}
	/* create empty rrset to store */
	neg = (struct ub_packed_rrset_key*)regional_alloc(env->scratch,
	                sizeof(struct ub_packed_rrset_key));
	if(!neg) {
		log_err("out of memory in store_parentside_neg");
		return;
	}
	memset(&neg->entry, 0, sizeof(neg->entry));
	neg->entry.key = neg;
	neg->rk.type = htons(qinfo->qtype);
	neg->rk.rrset_class = htons(qinfo->qclass);
	neg->rk.flags = 0;
	neg->rk.dname = regional_alloc_init(env->scratch, qinfo->qname,
		qinfo->qname_len);
	if(!neg->rk.dname) {
		log_err("out of memory in store_parentside_neg");
		return;
	}
	neg->rk.dname_len = qinfo->qname_len;
	neg->entry.hash = rrset_key_hash(&neg->rk);
	newd = (struct packed_rrset_data*)regional_alloc_zero(env->scratch,
		sizeof(struct packed_rrset_data) + sizeof(size_t) +
		sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t));
	if(!newd) {
		log_err("out of memory in store_parentside_neg");
		return;
	}
	neg->entry.data = newd;
	newd->ttl = ttl;
	/* entry must have one RR, otherwise not valid in cache.
	 * put in one RR with empty rdata: those are ignored as nameserver */
	newd->count = 1;
	newd->rrsig_count = 0;
	newd->trust = rrset_trust_ans_noAA;
	newd->rr_len = (size_t*)((uint8_t*)newd +
		sizeof(struct packed_rrset_data));
	newd->rr_len[0] = 0 /* zero len rdata */ + sizeof(uint16_t);
	packed_rrset_ptr_fixup(newd);
	newd->rr_ttl[0] = newd->ttl;
	sldns_write_uint16(newd->rr_data[0], 0 /* zero len rdata */);
	/* store it */
	log_rrset_key(VERB_ALGO, "store parent-side negative", neg);
	iter_store_parentside_rrset(env, neg);
}


deny_refuse_all(struct comm_point* c, enum acl_access acl,
	struct worker* worker, struct comm_reply* repinfo,
	struct acl_addr* acladdr, int ede)
{
	return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo,
		acladdr, ede);
}


int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
        uint16_t qflags, int prime, int valrec, struct module_qstate** newq)
{
	struct mesh_area* mesh = qstate->env->mesh;
	struct mesh_state* sub = NULL;
	int was_detached;
	if(!mesh_add_sub(qstate, qinfo, qflags, prime, valrec, newq, &sub))
		return 0;
	was_detached = (sub->super_set.count == 0);
	if(!mesh_state_attachment(qstate->mesh_info, sub))
		return 0;
	/* if it was a duplicate  attachment, the count was not zero before */
	if(!sub->reply_list && !sub->cb_list && was_detached &&
		sub->super_set.count == 1) {
		/* it used to be detached, before this one got added */
		log_assert(mesh->num_detached_states > 0);
		mesh->num_detached_states--;
	}
	/* *newq will be run when inited after the current module stops */
	return 1;
}


print_dp_main(RES* ssl, struct delegpt* dp, struct dns_msg* msg)
{
	size_t i, n_ns, n_miss, n_addr, n_res, n_avail;

	/* print the dp */
	if(msg)
	    for(i=0; i<msg->rep->rrset_count; i++) {
		struct ub_packed_rrset_key* k = msg->rep->rrsets[i];
		struct packed_rrset_data* d =
			(struct packed_rrset_data*)k->entry.data;
		if(d->security == sec_status_bogus) {
			if(!ssl_printf(ssl, "Address is BOGUS:\n"))
				return;
		}
		if(!dump_rrset(ssl, k, d, 0))
			return;
	    }
	delegpt_count_ns(dp, &n_ns, &n_miss);
	delegpt_count_addr(dp, &n_addr, &n_res, &n_avail);
	/* since dp has not been used by iterator, all are available*/
	if(!ssl_printf(ssl, "Delegation with %d names, of which %d "
		"can be examined to query further addresses.\n"
		"%sIt provides %d IP addresses.\n",
		(int)n_ns, (int)n_miss, (dp->bogus?"It is BOGUS. ":""),
		(int)n_addr))
		return;
}


iter_mark_cycle_targets(struct module_qstate* qstate, struct delegpt* dp)
{
	struct delegpt_ns* ns;
	for(ns = dp->nslist; ns; ns = ns->next) {
		if(ns->resolved)
			continue;
		/* see if this ns as target causes dependency cycle */
		if(causes_cycle(qstate, ns->name, ns->namelen,
			LDNS_RR_TYPE_AAAA, qstate->qinfo.qclass) ||
		   causes_cycle(qstate, ns->name, ns->namelen,
			LDNS_RR_TYPE_A, qstate->qinfo.qclass)) {
			log_nametypeclass(VERB_QUERY, "skipping target due "
			 	"to dependency cycle (harden-glue: no may "
				"fix some of the cycles)",
				ns->name, LDNS_RR_TYPE_A,
				qstate->qinfo.qclass);
			ns->resolved = 1;
		}
	}
}


void iterator_set_ip46_support(struct module_stack* mods,
	struct module_env* env, struct outside_network* outnet)
{
	int m = modstack_find(mods, "iterator");
	struct iter_env* ie = NULL;
	if(m == -1)
		return;
	ie = (struct iter_env*)env->modinfo[m];
	if(outnet->pending == NULL)
		return; /* we are in testbound, no rbtree for UDP */
	if(outnet->num_ip4 == 0)
		ie->supports_ipv4 = 0;
	if(outnet->num_ip6 == 0)
		ie->supports_ipv6 = 0;
}


mesh_get_mem(struct mesh_area* mesh)
{
	struct mesh_state* m;
	size_t s = sizeof(*mesh) + sizeof(struct timehist) +
		sizeof(struct th_buck)*mesh->histogram->num +
		sizeof(sldns_buffer) + sldns_buffer_capacity(mesh->qbuf_bak);
	RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
		/* all, including m itself allocated in qstate region */
		s += regional_get_mem(m->s.region);
	}
	return s;
}


rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
	time_t now, struct query_info* q)
{
	struct dns_msg* msg;
	struct packed_rrset_data* d = (struct packed_rrset_data*)
		rrset->entry.data;
	if(now > d->ttl)
		return NULL;
	msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */
	if(!msg)
		return NULL;
	msg->rep->flags = BIT_QR; /* reply, no AA, no error */
        msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
	msg->rep->qdcount = 1;
	msg->rep->ttl = d->ttl - now;
	msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
	msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
	msg->rep->security = sec_status_unchecked;
	msg->rep->an_numrrsets = 1;
	msg->rep->ns_numrrsets = 0;
	msg->rep->ar_numrrsets = 0;
	msg->rep->rrset_count = 1;
	msg->rep->reason_bogus = LDNS_EDE_NONE;
	msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
	if(!msg->rep->rrsets[0]) /* copy CNAME */
		return NULL;
	return msg;
}


mesh_delete(struct mesh_area* mesh)
{
	if(!mesh)
		return;
	/* free all query states */
	while(mesh->all.count)
		mesh_delete_helper(mesh->all.root);
	timehist_delete(mesh->histogram);
	sldns_buffer_free(mesh->qbuf_bak);
	free(mesh);
}


void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
        struct comm_reply* reply, int what)
{
	enum module_ev event = module_event_reply;
	e->qstate->reply = reply;
	if(what != NETEVENT_NOERROR) {
		event = module_event_noreply;
		if(what == NETEVENT_CAPSFAIL)
			event = module_event_capsfail;
	}
	mesh_run(mesh, e->qstate->mesh_info, event, e);
}


target_count_increase_nx(struct iter_qstate* iq, int num)
{
	target_count_create(iq);
	if(iq->target_count)
		iq->target_count[TARGET_COUNT_NX] += num;
}


mesh_stats(struct mesh_area* mesh, const char* str)
{
	verbose(VERB_DETAIL, "%s %u recursion states (%u with reply, "
		"%u detached), %u waiting replies, %u recursion replies "
		"sent, %d replies dropped, %d states jostled out",
		str, (unsigned)mesh->all.count,
		(unsigned)mesh->num_reply_states,
		(unsigned)mesh->num_detached_states,
		(unsigned)mesh->num_reply_addrs,
		(unsigned)mesh->replies_sent,
		(unsigned)mesh->stats_dropped,
		(unsigned)mesh->stats_jostled);
	if(mesh->replies_sent > 0) {
		struct timeval avg;
		timeval_divide(&avg, &mesh->replies_sum_wait,
			mesh->replies_sent);
		log_info("average recursion processing time "
			ARG_LL "d.%6.6d sec",
			(long long)avg.tv_sec, (int)avg.tv_usec);
		log_info("histogram of recursion processing times");
		timehist_log(mesh->histogram, "recursions");
	}
}


answer_from_cache(struct worker* worker, struct query_info* qinfo,
	struct respip_client_info* cinfo, int* need_drop, int* is_expired_answer,
	int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
	struct reply_info** partial_repp,
	struct reply_info* rep, uint16_t id, uint16_t flags,
	struct comm_reply* repinfo, struct edns_data* edns)
{
	time_t timenow = *worker->env.now;
	uint16_t udpsize = edns->udp_size;
	struct reply_info* encode_rep = rep;
	struct reply_info* partial_rep = *partial_repp;
	int must_validate = (!(flags&BIT_CD) || worker->env.cfg->ignore_cd)
		&& worker->env.need_to_validate;
	*partial_repp = NULL;  /* avoid accidental further pass */

	/* Check TTL */
	if(rep->ttl < timenow) {
		/* Check if we need to serve expired now */
		if(worker->env.cfg->serve_expired &&
			!worker->env.cfg->serve_expired_client_timeout) {
				if(worker->env.cfg->serve_expired_ttl &&
					rep->serve_expired_ttl < timenow)
					return 0;
				if(!rrset_array_lock(rep->ref, rep->rrset_count, 0))
					return 0;
				*is_expired_answer = 1;
		} else {
			/* the rrsets may have been updated in the meantime.
			 * we will refetch the message format from the
			 * authoritative server
			 */
			return 0;
		}
	} else {
		if(!rrset_array_lock(rep->ref, rep->rrset_count, timenow))
			return 0;
	}
	/* locked and ids and ttls are OK. */

	/* check CNAME chain (if any) */
	if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type ==
		htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type ==
		htons(LDNS_RR_TYPE_DNAME))) {
		if(!reply_check_cname_chain(qinfo, rep)) {
			/* cname chain invalid, redo iterator steps */
			verbose(VERB_ALGO, "Cache reply: cname chain broken");
			goto bail_out;
		}
	}
	/* check security status of the cached answer */
	if(must_validate && (rep->security == sec_status_bogus ||
		rep->security == sec_status_secure_sentinel_fail)) {
		/* BAD cached */
		edns->edns_version = EDNS_ADVERTISED_VERSION;
		edns->udp_size = EDNS_ADVERTISED_SIZE;
		edns->ext_rcode = 0;
		edns->bits &= EDNS_DO;
		if(!inplace_cb_reply_servfail_call(&worker->env, qinfo, NULL, rep,
			LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
			worker->env.now_tv))
			goto bail_out;
		/* TODO store the reason for the bogus reply in cache
		 * and implement in here instead of the hardcoded EDE */
		if (worker->env.cfg->ede) {
			EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
				worker->scratchpad, LDNS_EDE_DNSSEC_BOGUS, "");
		}
		error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
			qinfo, id, flags, edns);
		rrset_array_unlock_touch(worker->env.rrset_cache,
			worker->scratchpad, rep->ref, rep->rrset_count);
		if(worker->stats.extended) {
			worker->stats.ans_bogus ++;
			worker->stats.ans_rcode[LDNS_RCODE_SERVFAIL] ++;
		}
		return 1;
	} else if(rep->security == sec_status_unchecked && must_validate) {
		verbose(VERB_ALGO, "Cache reply: unchecked entry needs "
			"validation");
		goto bail_out; /* need to validate cache entry first */
	} else if(rep->security == sec_status_secure) {
		if(reply_all_rrsets_secure(rep)) {
			*is_secure_answer = 1;
		} else {
			if(must_validate) {
				verbose(VERB_ALGO, "Cache reply: secure entry"
					" changed status");
				goto bail_out; /* rrset changed, re-verify */
			}
			*is_secure_answer = 0;
		}
	} else *is_secure_answer = 0;

	edns->edns_version = EDNS_ADVERTISED_VERSION;
	edns->udp_size = EDNS_ADVERTISED_SIZE;
	edns->ext_rcode = 0;
	edns->bits &= EDNS_DO;
	if(!inplace_cb_reply_cache_call(&worker->env, qinfo, NULL, rep,
		(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad,
		worker->env.now_tv))
		goto bail_out;
	*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
	if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
		!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
		repinfo, alias_rrset,
		&encode_rep, worker->env.auth_zones)) {
		goto bail_out;
	} else if(partial_rep &&
		!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
		must_validate, &encode_rep, worker->scratchpad,
		worker->env.auth_zones)) {
		goto bail_out;
	}
	if(encode_rep != rep) {
		/* if rewritten, it can't be considered "secure" */
		*is_secure_answer = 0;
	}
	if(!encode_rep || *alias_rrset) {
		if(!encode_rep)
			*need_drop = 1;
		else {
			/* If a partial CNAME chain is found, we first need to
			 * make a copy of the reply in the scratchpad so we
			 * can release the locks and lookup the cache again. */
			*partial_repp = reply_info_copy(encode_rep, NULL,
				worker->scratchpad);
			if(!*partial_repp)
				goto bail_out;
		}
	} else {
		/* We don't check the global ede as this is a warning, not
		 * an error */
		if (*is_expired_answer == 1 &&
			worker->env.cfg->ede_serve_expired && worker->env.cfg->ede) {
			EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
				worker->scratchpad, LDNS_EDE_STALE_ANSWER, "");
		}
		if(!reply_info_answer_encode(qinfo, encode_rep, id, flags,
			repinfo->c->buffer, timenow, 1, worker->scratchpad,
			udpsize, edns, (int)(edns->bits & EDNS_DO),
			*is_secure_answer)) {
			if(!inplace_cb_reply_servfail_call(&worker->env, qinfo,
				NULL, NULL, LDNS_RCODE_SERVFAIL, edns, repinfo,
				worker->scratchpad, worker->env.now_tv))
					edns->opt_list_inplace_cb_out = NULL;
			error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
				qinfo, id, flags, edns);
		}
	}
	/* cannot send the reply right now, because blocking network syscall
	 * is bad while holding locks. */
	rrset_array_unlock_touch(worker->env.rrset_cache, worker->scratchpad,
		rep->ref, rep->rrset_count);
	/* go and return this buffer to the client */
	return 1;

bail_out:
	rrset_array_unlock_touch(worker->env.rrset_cache,
		worker->scratchpad, rep->ref, rep->rrset_count);
	return 0;
}


worker_send_cmd(struct worker* worker, enum worker_commands cmd)
{
	uint32_t c = (uint32_t)htonl(cmd);
	if(!tube_write_msg(worker->cmd, (uint8_t*)&c, sizeof(c), 0)) {
		log_err("worker send cmd %d failed", (int)cmd);
	}
}


void iter_dec_attempts(struct delegpt* dp, int d, int outbound_msg_retry)
{
	struct delegpt_addr* a;
	for(a=dp->target_list; a; a = a->next_target) {
		if(a->attempts >= outbound_msg_retry) {
			/* add back to result list */
			a->next_result = dp->result_list;
			dp->result_list = a;
		}
		if(a->attempts > d)
			a->attempts -= d;
		else a->attempts = 0;
	}
}


void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
	void* ATTR_UNUSED(arg))
{
	log_assert(0);
}


processFinished(struct module_qstate* qstate, struct val_qstate* vq,
	struct val_env* ve, int id)
{
	enum val_classification subtype = val_classify_response(
		qstate->query_flags, &qstate->qinfo, &vq->qchase,
		vq->orig_msg->rep, vq->rrset_skip);

	/* store overall validation result in orig_msg */
	if(vq->rrset_skip == 0) {
		vq->orig_msg->rep->security = vq->chase_reply->security;
		update_reason_bogus(vq->orig_msg->rep, vq->chase_reply->reason_bogus);
	} else if(subtype != VAL_CLASS_REFERRAL ||
		vq->rrset_skip < vq->orig_msg->rep->an_numrrsets +
		vq->orig_msg->rep->ns_numrrsets) {
		/* ignore sec status of additional section if a referral
		 * type message skips there and
		 * use the lowest security status as end result. */
		if(vq->chase_reply->security < vq->orig_msg->rep->security) {
			vq->orig_msg->rep->security =
				vq->chase_reply->security;
			update_reason_bogus(vq->orig_msg->rep, vq->chase_reply->reason_bogus);
		}
	}

	if(subtype == VAL_CLASS_REFERRAL) {
		/* for a referral, move to next unchecked rrset and check it*/
		vq->rrset_skip = val_next_unchecked(vq->orig_msg->rep,
			vq->rrset_skip);
		if(vq->rrset_skip < vq->orig_msg->rep->rrset_count) {
			/* and restart for this rrset */
			verbose(VERB_ALGO, "validator: go to next rrset");
			vq->chase_reply->security = sec_status_unchecked;
			vq->state = VAL_INIT_STATE;
			return 1;
		}
		/* referral chase is done */
	}
	if(vq->chase_reply->security != sec_status_bogus &&
		subtype == VAL_CLASS_CNAME) {
		/* chase the CNAME; process next part of the message */
		if(!val_chase_cname(&vq->qchase, vq->orig_msg->rep,
			&vq->rrset_skip)) {
			verbose(VERB_ALGO, "validator: failed to chase CNAME");
			vq->orig_msg->rep->security = sec_status_bogus;
			update_reason_bogus(vq->orig_msg->rep, LDNS_EDE_DNSSEC_BOGUS);
		} else {
			/* restart process for new qchase at rrset_skip */
			log_query_info(VERB_ALGO, "validator: chased to",
				&vq->qchase);
			vq->chase_reply->security = sec_status_unchecked;
			vq->state = VAL_INIT_STATE;
			return 1;
		}
	}

	if(vq->orig_msg->rep->security == sec_status_secure) {
		/* If the message is secure, check that all rrsets are
		 * secure (i.e. some inserted RRset for CNAME chain with
		 * a different signer name). And drop additional rrsets
		 * that are not secure (if clean-additional option is set) */
		/* this may cause the msg to be marked bogus */
		val_check_nonsecure(qstate->env, vq->orig_msg->rep);
		if(vq->orig_msg->rep->security == sec_status_secure) {
			log_query_info(VERB_DETAIL, "validation success",
				&qstate->qinfo);
			if(!qstate->no_cache_store) {
				val_neg_addreply(qstate->env->neg_cache,
					vq->orig_msg->rep);
			}
		}
	}

	/* if the result is bogus - set message ttl to bogus ttl to avoid
	 * endless bogus revalidation */
	if(vq->orig_msg->rep->security == sec_status_bogus) {
		/* see if we can try again to fetch data */
		if(vq->restart_count < ve->max_restart) {
			int restart_count = vq->restart_count+1;
			verbose(VERB_ALGO, "validation failed, "
				"blacklist and retry to fetch data");
			val_blacklist(&qstate->blacklist, qstate->region,
				qstate->reply_origin, 0);
			qstate->reply_origin = NULL;
			qstate->errinf = NULL;
			memset(vq, 0, sizeof(*vq));
			vq->restart_count = restart_count;
			vq->state = VAL_INIT_STATE;
			verbose(VERB_ALGO, "pass back to next module");
			qstate->ext_state[id] = module_restart_next;
			return 0;
		}

		vq->orig_msg->rep->ttl = ve->bogus_ttl;
		vq->orig_msg->rep->prefetch_ttl =
			PREFETCH_TTL_CALC(vq->orig_msg->rep->ttl);
		vq->orig_msg->rep->serve_expired_ttl =
			vq->orig_msg->rep->ttl + qstate->env->cfg->serve_expired_ttl;
		if((qstate->env->cfg->val_log_level >= 1 ||
			qstate->env->cfg->log_servfail) &&
			!qstate->env->cfg->val_log_squelch) {
			if(qstate->env->cfg->val_log_level < 2 &&
				!qstate->env->cfg->log_servfail)
				log_query_info(NO_VERBOSE, "validation failure",
					&qstate->qinfo);
			else {
				char* err = errinf_to_str_bogus(qstate);
				if(err) log_info("%s", err);
				free(err);
			}
		}
		/*
		 * If set, the validator will not make messages bogus, instead
		 * indeterminate is issued, so that no clients receive SERVFAIL.
		 * This allows an operator to run validation 'shadow' without
		 * hurting responses to clients.
		 */
		/* If we are in permissive mode, bogus gets indeterminate */
		if(qstate->env->cfg->val_permissive_mode)
			vq->orig_msg->rep->security = sec_status_indeterminate;
	}

	if(vq->orig_msg->rep->security == sec_status_secure &&
		qstate->env->cfg->root_key_sentinel &&
		(qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
		qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA)) {
		char* keytag_start;
		uint16_t keytag;
		if(*qstate->qinfo.qname == strlen(SENTINEL_IS) +
			SENTINEL_KEYTAG_LEN &&
			dname_lab_startswith(qstate->qinfo.qname, SENTINEL_IS,
			&keytag_start)) {
			if(sentinel_get_keytag(keytag_start, &keytag) &&
				!anchor_has_keytag(qstate->env->anchors,
				(uint8_t*)"", 1, 0, vq->qchase.qclass, keytag)) {
				vq->orig_msg->rep->security =
					sec_status_secure_sentinel_fail;
			}
		} else if(*qstate->qinfo.qname == strlen(SENTINEL_NOT) +
			SENTINEL_KEYTAG_LEN &&
			dname_lab_startswith(qstate->qinfo.qname, SENTINEL_NOT,
			&keytag_start)) {
			if(sentinel_get_keytag(keytag_start, &keytag) &&
				anchor_has_keytag(qstate->env->anchors,
				(uint8_t*)"", 1, 0, vq->qchase.qclass, keytag)) {
				vq->orig_msg->rep->security =
					sec_status_secure_sentinel_fail;
			}
		}
	}
	/* store results in cache */
	if(qstate->query_flags&BIT_RD) {
		/* if secure, this will override cache anyway, no need
		 * to check if from parentNS */
		if(!qstate->no_cache_store) {
			if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
				vq->orig_msg->rep, 0, qstate->prefetch_leeway, 0, NULL,
				qstate->query_flags, qstate->qstarttime)) {
				log_err("out of memory caching validator results");
			}
		}
	} else {
		/* for a referral, store the verified RRsets */
		/* and this does not get prefetched, so no leeway */
		if(!dns_cache_store(qstate->env, &vq->orig_msg->qinfo,
			vq->orig_msg->rep, 1, 0, 0, NULL,
			qstate->query_flags, qstate->qstarttime)) {
			log_err("out of memory caching validator results");
		}
	}
	qstate->return_rcode = LDNS_RCODE_NOERROR;
	qstate->return_msg = vq->orig_msg;
	qstate->ext_state[id] = module_finished;
	return 0;
}


dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
		struct outbound_entry* outbound)
{
	struct dns64_qstate* iq;
	(void)outbound;
	verbose(VERB_QUERY, "dns64[module %d] operate: extstate:%s event:%s",
			id, strextstate(qstate->ext_state[id]),
			strmodulevent(event));
	log_query_info(VERB_QUERY, "dns64 operate: query", &qstate->qinfo);

	switch(event) {
		case module_event_new:
			/* Tag this query as being new and fall through. */
			if (!(iq = (struct dns64_qstate*)regional_alloc(
				qstate->region, sizeof(*iq)))) {
				log_err("out of memory");
				qstate->ext_state[id] = module_error;
				return;
			}
			qstate->minfo[id] = iq;
			iq->state = DNS64_NEW_QUERY;
			iq->started_no_cache_store = qstate->no_cache_store;
			qstate->no_cache_store = 1;
  			/* fallthrough */
		case module_event_pass:
			qstate->ext_state[id] = handle_event_pass(qstate, id);
			break;
		case module_event_moddone:
			qstate->ext_state[id] = handle_event_moddone(qstate, id);
			break;
		default:
			qstate->ext_state[id] = module_finished;
			break;
	}
	if(qstate->ext_state[id] == module_finished) {
		iq = (struct dns64_qstate*)qstate->minfo[id];
		if(iq && iq->state != DNS64_INTERNAL_QUERY)
			qstate->no_cache_store = iq->started_no_cache_store;
	}
}


static void mesh_schedule_prefetch(struct mesh_area* mesh,
	struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
	int rpz_passthru)
{
	struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
		qflags&(BIT_RD|BIT_CD), 0, 0);
#ifdef UNBOUND_DEBUG
	struct rbnode_type* n;
#endif
	/* already exists, and for a different purpose perhaps.
	 * if mesh_no_list, keep it that way. */
	if(s) {
		/* make it ignore the cache from now on */
		if(!s->s.blacklist)
			sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
		if(s->s.prefetch_leeway < leeway)
			s->s.prefetch_leeway = leeway;
		return;
	}
	if(!mesh_make_new_space(mesh, NULL)) {
		verbose(VERB_ALGO, "Too many queries. dropped prefetch.");
		mesh->stats_dropped ++;
		return;
	}

	s = mesh_state_create(mesh->env, qinfo, NULL,
		qflags&(BIT_RD|BIT_CD), 0, 0);
	if(!s) {
		log_err("prefetch mesh_state_create: out of memory");
		return;
	}
#ifdef UNBOUND_DEBUG
	n =
#else
	(void)
#endif
	rbtree_insert(&mesh->all, &s->node);
	log_assert(n != NULL);
	/* set detached (it is now) */
	mesh->num_detached_states++;
	/* make it ignore the cache */
	sock_list_insert(&s->s.blacklist, NULL, 0, s->s.region);
	s->s.prefetch_leeway = leeway;

	if(s->list_select == mesh_no_list) {
		/* move to either the forever or the jostle_list */
		if(mesh->num_forever_states < mesh->max_forever_states) {
			mesh->num_forever_states ++;
			mesh_list_insert(s, &mesh->forever_first,
				&mesh->forever_last);
			s->list_select = mesh_forever_list;
		} else {
			mesh_list_insert(s, &mesh->jostle_first,
				&mesh->jostle_last);
			s->list_select = mesh_jostle_list;
		}
	}
	s->s.rpz_passthru = rpz_passthru;

	if(!run) {
#ifdef UNBOUND_DEBUG
		n =
#else
		(void)
#endif
		rbtree_insert(&mesh->run, &s->run_node);
		log_assert(n != NULL);
		return;
	}

	mesh_run(mesh, s, module_event_new, NULL);
}


cachedb_clear(struct module_qstate* qstate, int id)
{
	struct cachedb_qstate* iq;
	if(!qstate)
		return;
	iq = (struct cachedb_qstate*)qstate->minfo[id];
	if(iq) {
		/* free contents of iq */
		/* TODO */
	}
	qstate->minfo[id] = NULL;
}


dns64_always_synth_for_qname(struct module_qstate* qstate, int id)
{
	struct dns64_env* dns64_env = (struct dns64_env*)qstate->env->modinfo[id];
	int labs = dname_count_labels(qstate->qinfo.qname);
	struct name_tree_node* node = name_tree_lookup(&dns64_env->ignore_aaaa,
		qstate->qinfo.qname, qstate->qinfo.qname_len, labs,
		qstate->qinfo.qclass);
	return (node != NULL);
}


void dtio_tap_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev),
	void* ATTR_UNUSED(arg))
{
	log_assert(0);
}


prime_trust_anchor(struct module_qstate* qstate, struct val_qstate* vq,
	int id, struct trust_anchor* toprime)
{
	struct module_qstate* newq = NULL;
	int ret = generate_request(qstate, id, toprime->name, toprime->namelen,
		LDNS_RR_TYPE_DNSKEY, toprime->dclass, BIT_CD, &newq, 0);

	if(newq && qstate->env->cfg->trust_anchor_signaling &&
		!generate_keytag_query(qstate, id, toprime)) {
		verbose(VERB_ALGO, "keytag signaling query failed");
		return 0;
	}

	if(!ret) {
		verbose(VERB_ALGO, "Could not prime trust anchor");
		return 0;
	}
	/* ignore newq; validator does not need state created for that
	 * query, and its a 'normal' for iterator as well */
	vq->wait_prime_ta = 1; /* to elicit PRIME_RESP_STATE processing
		from the validator inform_super() routine */
	/* store trust anchor name for later lookup when prime returns */
	vq->trust_anchor_name = regional_alloc_init(qstate->region,
		toprime->name, toprime->namelen);
	vq->trust_anchor_len = toprime->namelen;
	vq->trust_anchor_labs = toprime->namelabs;
	if(!vq->trust_anchor_name) {
		log_err("Could not prime trust anchor: out of memory");
		return 0;
	}
	return 1;
}


already_validated(struct dns_msg* ret_msg)
{
	/* validate unchecked, and re-validate bogus messages */
	if (ret_msg && ret_msg->rep->security > sec_status_bogus)
	{
		verbose(VERB_ALGO, "response has already been validated: %s",
			sec_status_to_string(ret_msg->rep->security));
		return 1;
	}
	return 0;
}


deleg_remove_nonsecure_additional(struct reply_info* rep)
{
	/* we can simply edit it, since we are working in the scratch region */
	size_t i;
	enum sec_status s;

	for(i = rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) {
		s = ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
			->security;
		if(s != sec_status_secure) {
			memmove(rep->rrsets+i, rep->rrsets+i+1,
				sizeof(struct ub_packed_rrset_key*)*
				(rep->rrset_count - i - 1));
			rep->ar_numrrsets--;
			rep->rrset_count--;
			i--;
		}
	}
}


void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
	uint16_t qflags, time_t leeway, int rpz_passthru,
	struct comm_reply* rep, struct edns_option* opt_list)
{
	(void)opt_list;
	(void)rep;
#ifdef CLIENT_SUBNET
	if(rep)
		mesh_schedule_prefetch_subnet(mesh, qinfo, qflags, leeway, 1,
			rpz_passthru, rep, opt_list);
	else
#endif
		mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1,
			rpz_passthru);
}


validate_cname_noanswer_response(struct module_env* env, struct val_env* ve,
	struct query_info* qchase, struct reply_info* chase_reply,
	struct key_entry_key* kkey)
{
	int nodata_valid_nsec = 0; /* If true, then NODATA has been proven.*/
	uint8_t* ce = NULL; /* for wildcard nodata responses. This is the
				proven closest encloser. */
	uint8_t* wc = NULL; /* for wildcard nodata responses. wildcard nsec */
	int nxdomain_valid_nsec = 0; /* if true, nameerror has been proven */
	int nxdomain_valid_wnsec = 0;
	int nsec3s_seen = 0; /* nsec3s seen */
	struct ub_packed_rrset_key* s;
	size_t i;
	uint8_t* nsec_ce; /* Used to find the NSEC with the longest ce */
	int ce_labs = 0;
	int prev_ce_labs = 0;

	/* the AUTHORITY section */
	for(i=chase_reply->an_numrrsets; i<chase_reply->an_numrrsets+
		chase_reply->ns_numrrsets; i++) {
		s = chase_reply->rrsets[i];

		/* If we encounter an NSEC record, try to use it to prove
		 * NODATA. This needs to handle the ENT NODATA case.
		 * Also try to prove NAMEERROR, and absence of a wildcard */
		if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC) {
			if(nsec_proves_nodata(s, qchase, &wc)) {
				nodata_valid_nsec = 1;
				/* set wc encloser if wildcard applicable */
			}
			if(val_nsec_proves_name_error(s, qchase->qname)) {
				ce = nsec_closest_encloser(qchase->qname, s);
				nxdomain_valid_nsec = 1;
			}
			nsec_ce = nsec_closest_encloser(qchase->qname, s);
			ce_labs = dname_count_labels(nsec_ce);
			/* Use longest closest encloser to prove wildcard. */
			if(ce_labs > prev_ce_labs ||
			       (ce_labs == prev_ce_labs &&
				       nxdomain_valid_wnsec == 0)) {
			       if(val_nsec_proves_no_wc(s, qchase->qname,
				       qchase->qname_len))
				       nxdomain_valid_wnsec = 1;
			       else
				       nxdomain_valid_wnsec = 0;
			}
			prev_ce_labs = ce_labs;
			if(val_nsec_proves_insecuredelegation(s, qchase)) {
				verbose(VERB_ALGO, "delegation is insecure");
				chase_reply->security = sec_status_insecure;
				return;
			}
		} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_NSEC3) {
			nsec3s_seen = 1;
		}
	}

	/* check to see if we have a wildcard NODATA proof. */

	/* The wildcard NODATA is 1 NSEC proving that qname does not exists
	 * (and also proving what the closest encloser is), and 1 NSEC
	 * showing the matching wildcard, which must be *.closest_encloser. */
	if(wc && !ce)
		nodata_valid_nsec = 0;
	else if(wc && ce) {
		if(query_dname_compare(wc, ce) != 0) {
			nodata_valid_nsec = 0;
		}
	}
	if(nxdomain_valid_nsec && !nxdomain_valid_wnsec) {
		/* name error is missing wildcard denial proof */
		nxdomain_valid_nsec = 0;
	}

	if(nodata_valid_nsec && nxdomain_valid_nsec) {
		verbose(VERB_QUERY, "CNAMEchain to noanswer proves that name "
			"exists and not exists, bogus");
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		return;
	}
	if(!nodata_valid_nsec && !nxdomain_valid_nsec && nsec3s_seen) {
		int nodata;
		enum sec_status sec = nsec3_prove_nxornodata(env, ve,
			chase_reply->rrsets+chase_reply->an_numrrsets,
			chase_reply->ns_numrrsets, qchase, kkey, &nodata);
		if(sec == sec_status_insecure) {
			verbose(VERB_ALGO, "CNAMEchain to noanswer response "
				"is insecure");
			chase_reply->security = sec_status_insecure;
			return;
		} else if(sec == sec_status_secure) {
			if(nodata)
				nodata_valid_nsec = 1;
			else	nxdomain_valid_nsec = 1;
		}
	}

	if(!nodata_valid_nsec && !nxdomain_valid_nsec) {
		verbose(VERB_QUERY, "CNAMEchain to noanswer response failed "
			"to prove status with NSEC/NSEC3");
		if(verbosity >= VERB_ALGO)
			log_dns_msg("Failed CNAMEnoanswer", qchase, chase_reply);
		chase_reply->security = sec_status_bogus;
		update_reason_bogus(chase_reply, LDNS_EDE_DNSSEC_BOGUS);
		return;
	}

	if(nodata_valid_nsec)
		verbose(VERB_ALGO, "successfully validated CNAME chain to a "
			"NODATA response.");
	else	verbose(VERB_ALGO, "successfully validated CNAME chain to a "
			"NAMEERROR response.");
	chase_reply->security = sec_status_secure;
}


void rose_add_loopback_neigh(void)
{
	struct rose_neigh *sn;

	rose_loopback_neigh = kmalloc(sizeof(struct rose_neigh), GFP_KERNEL);
	if (!rose_loopback_neigh)
		return;
	sn = rose_loopback_neigh;

	sn->callsign  = null_ax25_address;
	sn->digipeat  = NULL;
	sn->ax25      = NULL;
	sn->dev       = NULL;
	sn->count     = 0;
	sn->use       = 0;
	sn->dce_mode  = 1;
	sn->loopback  = 1;
	sn->number    = rose_neigh_no++;
	sn->restarted = 1;

	skb_queue_head_init(&sn->queue);

	timer_setup(&sn->ftimer, NULL, 0);
	timer_setup(&sn->t0timer, NULL, 0);

	spin_lock_bh(&rose_neigh_list_lock);
	sn->next = rose_neigh_list;
	rose_neigh_list           = sn;
	spin_unlock_bh(&rose_neigh_list_lock);
}


http_Status2Reason(unsigned status, const char **sstr)
{
	struct http_msg *mp;

	status %= 1000;
	assert(status >= 100);
	for (mp = http_msg; mp->nbr != 0 && mp->nbr <= status; mp++)
		if (mp->nbr == status) {
			if (sstr)
				*sstr = mp->status;
			return (mp->txt);
		}
	return ("Unknown HTTP Status");
}


http_EstimateWS(const struct http *fm, unsigned how)
{
	unsigned u, l;

	l = 4;
	CHECK_OBJ_NOTNULL(fm, HTTP_MAGIC);
	for (u = 0; u < fm->nhd; u++) {
		if (u == HTTP_HDR_METHOD || u == HTTP_HDR_URL)
			continue;
		Tcheck(fm->hd[u]);
		if (http_isfiltered(fm, u, how))
			continue;
		l += Tlen(fm->hd[u]) + 1L;
	}
	return (PRNDUP(l + 1L));
}


http_init_hdr(char *hdr, int flg)
{
	struct http_hdrflg *f;

	hdr[0] = strlen(hdr + 1);
	f = http_hdr_flags(hdr + 1, hdr + hdr[0]);
	if (flg) {
		AN(f);
		assert(f->hdr == hdr);
		f->flag = flg;
	}
}


http_DoConnection(struct http *hp, stream_close_t sc_close)
{
	const char *h, *b, *e;
	stream_close_t retval;
	unsigned u, v;
	struct http_hdrflg *f;

	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
	assert(sc_close == SC_REQ_CLOSE || sc_close == SC_RESP_CLOSE);

	if (hp->protover == 10)
		retval = SC_REQ_HTTP10;
	else
		retval = SC_NULL;

	http_CollectHdr(hp, H_Connection);
	if (!http_GetHdr(hp, H_Connection, &h))
		return (retval);
	AN(h);
	while (http_split(&h, NULL, ",", &b, &e)) {
		u = pdiff(b, e);
		if (u == 5 && http_hdr_at(b, "close", u))
			retval = sc_close;
		if (u == 10 && http_hdr_at(b, "keep-alive", u))
			retval = SC_NULL;

		/* Refuse removal of well-known-headers if they would pass. */
		f = http_hdr_flags(b, e);
		if (f != NULL && !(f->flag & HTTPH_R_PASS))
			return (SC_RX_BAD);

		for (v = HTTP_HDR_FIRST; v < hp->nhd; v++) {
			Tcheck(hp->hd[v]);
			if (hp->hd[v].e < hp->hd[v].b + u + 1)
				continue;
			if (hp->hd[v].b[u] != ':')
				continue;
			if (!http_hdr_at(b, hp->hd[v].b, u))
				continue;
			hp->hdf[v] |= HDF_FILTER;
		}
	}
	CHECK_OBJ_NOTNULL(retval, STREAM_CLOSE_MAGIC);
	return (retval);
}


http_GetMethod(const struct http *hp)
{

	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
	Tcheck(hp->hd[HTTP_HDR_METHOD]);
	return (hp->hd[HTTP_HDR_METHOD].b);
}


http_CollectHdrSep(struct http *hp, hdr_t hdr, const char *sep)
{
	unsigned u, l, lsep, ml, f, x, d;
	char *b = NULL, *e = NULL;
	const char *v;

	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
	if (WS_Overflowed(hp->ws))
		return;

	if (sep == NULL || *sep == '\0')
		sep = ", ";
	lsep = strlen(sep);

	l = hdr[0];
	assert(l == strlen(hdr + 1));
	assert(hdr[l] == ':');
	f = http_findhdr(hp, l - 1, hdr + 1);
	if (f == 0)
		return;

	for (d = u = f + 1; u < hp->nhd; u++) {
		Tcheck(hp->hd[u]);
		if (!http_IsHdr(&hp->hd[u], hdr)) {
			if (d != u) {
				hp->hd[d] = hp->hd[u];
				hp->hdf[d] = hp->hdf[u];
			}
			d++;
			continue;
		}
		if (b == NULL) {
			/* Found second header, start our collection */
			ml = WS_ReserveAll(hp->ws);
			b = WS_Reservation(hp->ws);
			e = b + ml;
			x = Tlen(hp->hd[f]);
			if (b + x >= e) {
				http_fail(hp);
				VSLbs(hp->vsl, SLT_LostHeader,
				    TOSTRAND(hdr + 1));
				WS_Release(hp->ws, 0);
				return;
			}
			memcpy(b, hp->hd[f].b, x);
			b += x;
		}

		AN(b);
		AN(e);

		/* Append the Nth header we found */
		x = Tlen(hp->hd[u]) - l;

		v = hp->hd[u].b + *hdr;
		while (vct_issp(*v)) {
			v++;
			x--;
		}

		if (b + lsep + x >= e) {
			http_fail(hp);
			VSLbs(hp->vsl, SLT_LostHeader, TOSTRAND(hdr + 1));
			WS_Release(hp->ws, 0);
			return;
		}
		memcpy(b, sep, lsep);
		b += lsep;
		memcpy(b, v, x);
		b += x;
	}
	if (b == NULL)
		return;
	hp->nhd = (uint16_t)d;
	AN(e);
	*b = '\0';
	hp->hd[f].b = WS_Reservation(hp->ws);
	hp->hd[f].e = b;
	WS_ReleaseP(hp->ws, b + 1);
}


HTTP_create(void *p, uint16_t nhttp, unsigned len)
{
	struct http *hp;

	hp = p;
	hp->magic = HTTP_MAGIC;
	hp->hd = (void*)(hp + 1);
	hp->shd = nhttp;
	hp->hdf = (void*)(hp->hd + nhttp);
	assert((unsigned char*)p + len == hp->hdf + PRNDUP(nhttp));
	return (hp);
}


HTTP_Clone(struct http *to, const struct http * const fm)
{

	HTTP_Dup(to, fm);
	to->vsl = fm->vsl;
	to->ws = fm->ws;
}


static int ismt_access(struct i2c_adapter *adap, u16 addr,
		       unsigned short flags, char read_write, u8 command,
		       int size, union i2c_smbus_data *data)
{
	int ret;
	unsigned long time_left;
	dma_addr_t dma_addr = 0; /* address of the data buffer */
	u8 dma_size = 0;
	enum dma_data_direction dma_direction = 0;
	struct ismt_desc *desc;
	struct ismt_priv *priv = i2c_get_adapdata(adap);
	struct device *dev = &priv->pci_dev->dev;
	u8 *dma_buffer = PTR_ALIGN(&priv->buffer[0], 16);

	desc = &priv->hw[priv->head];

	/* Initialize the DMA buffer */
	memset(priv->buffer, 0, sizeof(priv->buffer));

	/* Initialize the descriptor */
	memset(desc, 0, sizeof(struct ismt_desc));
	desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);

	/* Always clear the log entries */
	memset(priv->log, 0, ISMT_LOG_ENTRIES * sizeof(u32));

	/* Initialize common control bits */
	if (likely(pci_dev_msi_enabled(priv->pci_dev)))
		desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
	else
		desc->control = ISMT_DESC_FAIR;

	if ((flags & I2C_CLIENT_PEC) && (size != I2C_SMBUS_QUICK)
	    && (size != I2C_SMBUS_I2C_BLOCK_DATA))
		desc->control |= ISMT_DESC_PEC;

	switch (size) {
	case I2C_SMBUS_QUICK:
		dev_dbg(dev, "I2C_SMBUS_QUICK\n");
		break;

	case I2C_SMBUS_BYTE:
		if (read_write == I2C_SMBUS_WRITE) {
			/*
			 * Send Byte
			 * The command field contains the write data
			 */
			dev_dbg(dev, "I2C_SMBUS_BYTE:  WRITE\n");
			desc->control |= ISMT_DESC_CWRL;
			desc->wr_len_cmd = command;
		} else {
			/* Receive Byte */
			dev_dbg(dev, "I2C_SMBUS_BYTE:  READ\n");
			dma_size = 1;
			dma_direction = DMA_FROM_DEVICE;
			desc->rd_len = 1;
		}
		break;

	case I2C_SMBUS_BYTE_DATA:
		if (read_write == I2C_SMBUS_WRITE) {
			/*
			 * Write Byte
			 * Command plus 1 data byte
			 */
			dev_dbg(dev, "I2C_SMBUS_BYTE_DATA:  WRITE\n");
			desc->wr_len_cmd = 2;
			dma_size = 2;
			dma_direction = DMA_TO_DEVICE;
			dma_buffer[0] = command;
			dma_buffer[1] = data->byte;
		} else {
			/* Read Byte */
			dev_dbg(dev, "I2C_SMBUS_BYTE_DATA:  READ\n");
			desc->control |= ISMT_DESC_CWRL;
			desc->wr_len_cmd = command;
			desc->rd_len = 1;
			dma_size = 1;
			dma_direction = DMA_FROM_DEVICE;
		}
		break;

	case I2C_SMBUS_WORD_DATA:
		if (read_write == I2C_SMBUS_WRITE) {
			/* Write Word */
			dev_dbg(dev, "I2C_SMBUS_WORD_DATA:  WRITE\n");
			desc->wr_len_cmd = 3;
			dma_size = 3;
			dma_direction = DMA_TO_DEVICE;
			dma_buffer[0] = command;
			dma_buffer[1] = data->word & 0xff;
			dma_buffer[2] = data->word >> 8;
		} else {
			/* Read Word */
			dev_dbg(dev, "I2C_SMBUS_WORD_DATA:  READ\n");
			desc->wr_len_cmd = command;
			desc->control |= ISMT_DESC_CWRL;
			desc->rd_len = 2;
			dma_size = 2;
			dma_direction = DMA_FROM_DEVICE;
		}
		break;

	case I2C_SMBUS_PROC_CALL:
		dev_dbg(dev, "I2C_SMBUS_PROC_CALL\n");
		desc->wr_len_cmd = 3;
		desc->rd_len = 2;
		dma_size = 3;
		dma_direction = DMA_BIDIRECTIONAL;
		dma_buffer[0] = command;
		dma_buffer[1] = data->word & 0xff;
		dma_buffer[2] = data->word >> 8;
		break;

	case I2C_SMBUS_BLOCK_DATA:
		if (read_write == I2C_SMBUS_WRITE) {
			/* Block Write */
			dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA:  WRITE\n");
			dma_size = data->block[0] + 1;
			dma_direction = DMA_TO_DEVICE;
			desc->wr_len_cmd = dma_size;
			desc->control |= ISMT_DESC_BLK;
			dma_buffer[0] = command;
			memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
		} else {
			/* Block Read */
			dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA:  READ\n");
			dma_size = I2C_SMBUS_BLOCK_MAX;
			dma_direction = DMA_FROM_DEVICE;
			desc->rd_len = dma_size;
			desc->wr_len_cmd = command;
			desc->control |= (ISMT_DESC_BLK | ISMT_DESC_CWRL);
		}
		break;

	case I2C_SMBUS_BLOCK_PROC_CALL:
		dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n");
		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
			return -EINVAL;

		dma_size = I2C_SMBUS_BLOCK_MAX;
		desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1);
		desc->wr_len_cmd = data->block[0] + 1;
		desc->rd_len = dma_size;
		desc->control |= ISMT_DESC_BLK;
		dma_direction = DMA_BIDIRECTIONAL;
		dma_buffer[0] = command;
		memcpy(&dma_buffer[1], &data->block[1], data->block[0]);
		break;

	case I2C_SMBUS_I2C_BLOCK_DATA:
		/* Make sure the length is valid */
		if (data->block[0] < 1)
			data->block[0] = 1;

		if (data->block[0] > I2C_SMBUS_BLOCK_MAX)
			data->block[0] = I2C_SMBUS_BLOCK_MAX;

		if (read_write == I2C_SMBUS_WRITE) {
			/* i2c Block Write */
			dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA:  WRITE\n");
			dma_size = data->block[0] + 1;
			dma_direction = DMA_TO_DEVICE;
			desc->wr_len_cmd = dma_size;
			desc->control |= ISMT_DESC_I2C;
			dma_buffer[0] = command;
			memcpy(&dma_buffer[1], &data->block[1], dma_size - 1);
		} else {
			/* i2c Block Read */
			dev_dbg(dev, "I2C_SMBUS_I2C_BLOCK_DATA:  READ\n");
			dma_size = data->block[0];
			dma_direction = DMA_FROM_DEVICE;
			desc->rd_len = dma_size;
			desc->wr_len_cmd = command;
			desc->control |= (ISMT_DESC_I2C | ISMT_DESC_CWRL);
			/*
			 * Per the "Table 15-15. I2C Commands",
			 * in the External Design Specification (EDS),
			 * (Document Number: 508084, Revision: 2.0),
			 * the _rw bit must be 0
			 */
			desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 0);
		}
		break;

	default:
		dev_err(dev, "Unsupported transaction %d\n",
			size);
		return -EOPNOTSUPP;
	}

	/* map the data buffer */
	if (dma_size != 0) {
		dev_dbg(dev, " dev=%p\n", dev);
		dev_dbg(dev, " data=%p\n", data);
		dev_dbg(dev, " dma_buffer=%p\n", dma_buffer);
		dev_dbg(dev, " dma_size=%d\n", dma_size);
		dev_dbg(dev, " dma_direction=%d\n", dma_direction);

		dma_addr = dma_map_single(dev,
				      dma_buffer,
				      dma_size,
				      dma_direction);

		if (dma_mapping_error(dev, dma_addr)) {
			dev_err(dev, "Error in mapping dma buffer %p\n",
				dma_buffer);
			return -EIO;
		}

		dev_dbg(dev, " dma_addr = %pad\n", &dma_addr);

		desc->dptr_low = lower_32_bits(dma_addr);
		desc->dptr_high = upper_32_bits(dma_addr);
	}

	reinit_completion(&priv->cmp);

	/* Add the descriptor */
	ismt_submit_desc(priv);

	/* Now we wait for interrupt completion, 1s */
	time_left = wait_for_completion_timeout(&priv->cmp, HZ*1);

	/* unmap the data buffer */
	if (dma_size != 0)
		dma_unmap_single(dev, dma_addr, dma_size, dma_direction);

	if (unlikely(!time_left)) {
		dev_err(dev, "completion wait timed out\n");
		ret = -ETIMEDOUT;
		goto out;
	}

	/* do any post processing of the descriptor here */
	ret = ismt_process_desc(desc, data, priv, size, read_write);

out:
	/* Update the ring pointer */
	priv->head++;
	priv->head %= ISMT_DESC_ENTRIES;

	return ret;
}


ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
	int err;
	struct ismt_priv *priv;
	unsigned long start, len;

	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	pci_set_drvdata(pdev, priv);

	i2c_set_adapdata(&priv->adapter, priv);
	priv->adapter.owner = THIS_MODULE;
	priv->adapter.class = I2C_CLASS_HWMON;
	priv->adapter.algo = &smbus_algorithm;
	priv->adapter.dev.parent = &pdev->dev;
	ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev));
	priv->adapter.retries = ISMT_MAX_RETRIES;

	priv->pci_dev = pdev;

	err = pcim_enable_device(pdev);
	if (err) {
		dev_err(&pdev->dev, "Failed to enable SMBus PCI device (%d)\n",
			err);
		return err;
	}

	/* enable bus mastering */
	pci_set_master(pdev);

	/* Determine the address of the SMBus area */
	start = pci_resource_start(pdev, SMBBAR);
	len = pci_resource_len(pdev, SMBBAR);
	if (!start || !len) {
		dev_err(&pdev->dev,
			"SMBus base address uninitialized, upgrade BIOS\n");
		return -ENODEV;
	}

	snprintf(priv->adapter.name, sizeof(priv->adapter.name),
		 "SMBus iSMT adapter at %lx", start);

	dev_dbg(&priv->pci_dev->dev, " start=0x%lX\n", start);
	dev_dbg(&priv->pci_dev->dev, " len=0x%lX\n", len);

	err = acpi_check_resource_conflict(&pdev->resource[SMBBAR]);
	if (err) {
		dev_err(&pdev->dev, "ACPI resource conflict!\n");
		return err;
	}

	err = pci_request_region(pdev, SMBBAR, ismt_driver.name);
	if (err) {
		dev_err(&pdev->dev,
			"Failed to request SMBus region 0x%lx-0x%lx\n",
			start, start + len);
		return err;
	}

	priv->smba = pcim_iomap(pdev, SMBBAR, len);
	if (!priv->smba) {
		dev_err(&pdev->dev, "Unable to ioremap SMBus BAR\n");
		return -ENODEV;
	}

	err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
	if (err) {
		err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
		if (err) {
			dev_err(&pdev->dev, "dma_set_mask fail\n");
			return -ENODEV;
		}
	}

	err = ismt_dev_init(priv);
	if (err)
		return err;

	ismt_hw_init(priv);

	err = ismt_int_init(priv);
	if (err)
		return err;

	err = i2c_add_adapter(&priv->adapter);
	if (err)
		return -ENODEV;
	return 0;
}


static int cgroup_vet_subtree_control_enable(struct cgroup *cgrp, u16 enable)
{
	u16 domain_enable = enable & ~cgrp_dfl_threaded_ss_mask;

	/* if nothing is getting enabled, nothing to worry about */
	if (!enable)
		return 0;

	/* can @cgrp host any resources? */
	if (!cgroup_is_valid_domain(cgrp->dom_cgrp))
		return -EOPNOTSUPP;

	/* mixables don't care */
	if (cgroup_is_mixable(cgrp))
		return 0;

	if (domain_enable) {
		/* can't enable domain controllers inside a thread subtree */
		if (cgroup_is_thread_root(cgrp) || cgroup_is_threaded(cgrp))
			return -EOPNOTSUPP;
	} else {
		/*
		 * Threaded controllers can handle internal competitions
		 * and are always allowed inside a (prospective) thread
		 * subtree.
		 */
		if (cgroup_can_be_thread_root(cgrp) || cgroup_is_threaded(cgrp))
			return 0;
	}

	/*
	 * Controllers can't be enabled for a cgroup with tasks to avoid
	 * child cgroups competing against tasks.
	 */
	if (cgroup_has_tasks(cgrp))
		return -EBUSY;

	return 0;
}


static void cgroup_get_live(struct cgroup *cgrp)
{
	WARN_ON_ONCE(cgroup_is_dead(cgrp));
	css_get(&cgrp->self);
}


int cgroup_can_fork(struct task_struct *child, struct kernel_clone_args *kargs)
{
	struct cgroup_subsys *ss;
	int i, j, ret;

	ret = cgroup_css_set_fork(kargs);
	if (ret)
		return ret;

	do_each_subsys_mask(ss, i, have_canfork_callback) {
		ret = ss->can_fork(child, kargs->cset);
		if (ret)
			goto out_revert;
	} while_each_subsys_mask();

	return 0;

out_revert:
	for_each_subsys(ss, j) {
		if (j >= i)
			break;
		if (ss->cancel_fork)
			ss->cancel_fork(child, kargs->cset);
	}

	cgroup_css_set_put_fork(kargs);

	return ret;
}


static void offline_css(struct cgroup_subsys_state *css)
{
	struct cgroup_subsys *ss = css->ss;

	lockdep_assert_held(&cgroup_mutex);

	if (!(css->flags & CSS_ONLINE))
		return;

	if (ss->css_offline)
		ss->css_offline(css);

	css->flags &= ~CSS_ONLINE;
	RCU_INIT_POINTER(css->cgroup->subsys[ss->id], NULL);

	wake_up_all(&css->cgroup->offline_waitq);
}


static umode_t cgroup_file_mode(const struct cftype *cft)
{
	umode_t mode = 0;

	if (cft->read_u64 || cft->read_s64 || cft->seq_show)
		mode |= S_IRUGO;

	if (cft->write_u64 || cft->write_s64 || cft->write) {
		if (cft->flags & CFTYPE_WORLD_WRITABLE)
			mode |= S_IWUGO;
		else
			mode |= S_IWUSR;
	}

	return mode;
}


int cgroup_rmdir(struct kernfs_node *kn)
{
	struct cgroup *cgrp;
	int ret = 0;

	cgrp = cgroup_kn_lock_live(kn, false);
	if (!cgrp)
		return 0;

	ret = cgroup_destroy_locked(cgrp);
	if (!ret)
		TRACE_CGROUP_PATH(rmdir, cgrp);

	cgroup_kn_unlock(kn);
	return ret;
}


void css_task_iter_start(struct cgroup_subsys_state *css, unsigned int flags,
			 struct css_task_iter *it)
{
	memset(it, 0, sizeof(*it));

	spin_lock_irq(&css_set_lock);

	it->ss = css->ss;
	it->flags = flags;

	if (CGROUP_HAS_SUBSYS_CONFIG && it->ss)
		it->cset_pos = &css->cgroup->e_csets[css->ss->id];
	else
		it->cset_pos = &css->cgroup->cset_links;

	it->cset_head = it->cset_pos;

	css_task_iter_advance(it);

	spin_unlock_irq(&css_set_lock);
}


static void __cgroup_kill(struct cgroup *cgrp)
{
	struct css_task_iter it;
	struct task_struct *task;

	lockdep_assert_held(&cgroup_mutex);

	spin_lock_irq(&css_set_lock);
	set_bit(CGRP_KILL, &cgrp->flags);
	spin_unlock_irq(&css_set_lock);

	css_task_iter_start(&cgrp->self, CSS_TASK_ITER_PROCS | CSS_TASK_ITER_THREADED, &it);
	while ((task = css_task_iter_next(&it))) {
		/* Ignore kernel threads here. */
		if (task->flags & PF_KTHREAD)
			continue;

		/* Skip tasks that are already dying. */
		if (__fatal_signal_pending(task))
			continue;

		send_sig(SIGKILL, task, 0);
	}
	css_task_iter_end(&it);

	spin_lock_irq(&css_set_lock);
	clear_bit(CGRP_KILL, &cgrp->flags);
	spin_unlock_irq(&css_set_lock);
}


void cgroup_release(struct task_struct *task)
{
	struct cgroup_subsys *ss;
	int ssid;

	do_each_subsys_mask(ss, ssid, have_release_callback) {
		ss->release(task);
	} while_each_subsys_mask();

	spin_lock_irq(&css_set_lock);
	css_set_skip_task_iters(task_css_set(task), task);
	list_del_init(&task->cg_list);
	spin_unlock_irq(&css_set_lock);
}


static struct cgroup_subsys_state *cgroup_tryget_css(struct cgroup *cgrp,
						     struct cgroup_subsys *ss)
{
	struct cgroup_subsys_state *css;

	rcu_read_lock();
	css = cgroup_css(cgrp, ss);
	if (css && !css_tryget_online(css))
		css = NULL;
	rcu_read_unlock();

	return css;
}


int __init cgroup_init(void)
{
	struct cgroup_subsys *ss;
	int ssid;

	BUILD_BUG_ON(CGROUP_SUBSYS_COUNT > 16);
	BUG_ON(cgroup_init_cftypes(NULL, cgroup_base_files));
	BUG_ON(cgroup_init_cftypes(NULL, cgroup1_base_files));

	cgroup_rstat_boot();

	/*
	 * The latency of the synchronize_rcu() is too high for cgroups,
	 * avoid it at the cost of forcing all readers into the slow path.
	 */
	rcu_sync_enter_start(&cgroup_threadgroup_rwsem.rss);

	get_user_ns(init_cgroup_ns.user_ns);

	mutex_lock(&cgroup_mutex);

	/*
	 * Add init_css_set to the hash table so that dfl_root can link to
	 * it during init.
	 */
	hash_add(css_set_table, &init_css_set.hlist,
		 css_set_hash(init_css_set.subsys));

	BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0));

	mutex_unlock(&cgroup_mutex);

	for_each_subsys(ss, ssid) {
		if (ss->early_init) {
			struct cgroup_subsys_state *css =
				init_css_set.subsys[ss->id];

			css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2,
						   GFP_KERNEL);
			BUG_ON(css->id < 0);
		} else {
			cgroup_init_subsys(ss, false);
		}

		list_add_tail(&init_css_set.e_cset_node[ssid],
			      &cgrp_dfl_root.cgrp.e_csets[ssid]);

		/*
		 * Setting dfl_root subsys_mask needs to consider the
		 * disabled flag and cftype registration needs kmalloc,
		 * both of which aren't available during early_init.
		 */
		if (!cgroup_ssid_enabled(ssid))
			continue;

		if (cgroup1_ssid_disabled(ssid))
			printk(KERN_INFO "Disabling %s control group subsystem in v1 mounts\n",
			       ss->name);

		cgrp_dfl_root.subsys_mask |= 1 << ss->id;

		/* implicit controllers must be threaded too */
		WARN_ON(ss->implicit_on_dfl && !ss->threaded);

		if (ss->implicit_on_dfl)
			cgrp_dfl_implicit_ss_mask |= 1 << ss->id;
		else if (!ss->dfl_cftypes)
			cgrp_dfl_inhibit_ss_mask |= 1 << ss->id;

		if (ss->threaded)
			cgrp_dfl_threaded_ss_mask |= 1 << ss->id;

		if (ss->dfl_cftypes == ss->legacy_cftypes) {
			WARN_ON(cgroup_add_cftypes(ss, ss->dfl_cftypes));
		} else {
			WARN_ON(cgroup_add_dfl_cftypes(ss, ss->dfl_cftypes));
			WARN_ON(cgroup_add_legacy_cftypes(ss, ss->legacy_cftypes));
		}

		if (ss->bind)
			ss->bind(init_css_set.subsys[ssid]);

		mutex_lock(&cgroup_mutex);
		css_populate_dir(init_css_set.subsys[ssid]);
		mutex_unlock(&cgroup_mutex);
	}

	/* init_css_set.subsys[] has been updated, re-hash */
	hash_del(&init_css_set.hlist);
	hash_add(css_set_table, &init_css_set.hlist,
		 css_set_hash(init_css_set.subsys));

	WARN_ON(sysfs_create_mount_point(fs_kobj, "cgroup"));
	WARN_ON(register_filesystem(&cgroup_fs_type));
	WARN_ON(register_filesystem(&cgroup2_fs_type));
	WARN_ON(!proc_create_single("cgroups", 0, NULL, proc_cgroupstats_show));
#ifdef CONFIG_CPUSETS
	WARN_ON(register_filesystem(&cpuset_fs_type));
#endif

	return 0;
}


static struct psi_group *iterate_groups(struct task_struct *task, void **iter)
{
	if (*iter == &psi_system)
		return NULL;

#ifdef CONFIG_CGROUPS
	if (static_branch_likely(&psi_cgroups_enabled)) {
		struct cgroup *cgroup = NULL;

		if (!*iter)
			cgroup = task->cgroups->dfl_cgrp;
		else
			cgroup = cgroup_parent(*iter);

		if (cgroup && cgroup_parent(cgroup)) {
			*iter = cgroup;
			return cgroup_psi(cgroup);
		}
	}
#endif
	*iter = &psi_system;
	return &psi_system;
}


bool cgroup_psi_enabled(void)
{
	return (cgroup_feature_disable_mask & (1 << OPT_FEATURE_PRESSURE)) == 0;
}


void css_task_iter_end(struct css_task_iter *it)
{
	if (it->cur_cset) {
		spin_lock_irq(&css_set_lock);
		list_del(&it->iters_node);
		put_css_set_locked(it->cur_cset);
		spin_unlock_irq(&css_set_lock);
	}

	if (it->cur_dcset)
		put_css_set(it->cur_dcset);

	if (it->cur_task)
		put_task_struct(it->cur_task);
}


int cgroup_migrate_prepare_dst(struct cgroup_mgctx *mgctx)
{
	struct css_set *src_cset, *tmp_cset;

	lockdep_assert_held(&cgroup_mutex);

	/* look up the dst cset for each src cset and link it to src */
	list_for_each_entry_safe(src_cset, tmp_cset, &mgctx->preloaded_src_csets,
				 mg_preload_node) {
		struct css_set *dst_cset;
		struct cgroup_subsys *ss;
		int ssid;

		dst_cset = find_css_set(src_cset, src_cset->mg_dst_cgrp);
		if (!dst_cset)
			return -ENOMEM;

		WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset);

		/*
		 * If src cset equals dst, it's noop.  Drop the src.
		 * cgroup_migrate() will skip the cset too.  Note that we
		 * can't handle src == dst as some nodes are used by both.
		 */
		if (src_cset == dst_cset) {
			src_cset->mg_src_cgrp = NULL;
			src_cset->mg_dst_cgrp = NULL;
			list_del_init(&src_cset->mg_preload_node);
			put_css_set(src_cset);
			put_css_set(dst_cset);
			continue;
		}

		src_cset->mg_dst_cset = dst_cset;

		if (list_empty(&dst_cset->mg_preload_node))
			list_add_tail(&dst_cset->mg_preload_node,
				      &mgctx->preloaded_dst_csets);
		else
			put_css_set(dst_cset);

		for_each_subsys(ss, ssid)
			if (src_cset->subsys[ssid] != dst_cset->subsys[ssid])
				mgctx->ss_mask |= 1 << ssid;
	}

	return 0;
}


static int cgroup_file_open(struct kernfs_open_file *of)
{
	struct cftype *cft = of_cft(of);
	struct cgroup_file_ctx *ctx;
	int ret;

	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;

	ctx->ns = current->nsproxy->cgroup_ns;
	get_cgroup_ns(ctx->ns);
	of->priv = ctx;

	if (!cft->open)
		return 0;

	ret = cft->open(of);
	if (ret) {
		put_cgroup_ns(ctx->ns);
		kfree(ctx);
	}
	return ret;
}


static void css_release_work_fn(struct work_struct *work)
{
	struct cgroup_subsys_state *css =
		container_of(work, struct cgroup_subsys_state, destroy_work);
	struct cgroup_subsys *ss = css->ss;
	struct cgroup *cgrp = css->cgroup;

	mutex_lock(&cgroup_mutex);

	css->flags |= CSS_RELEASED;
	list_del_rcu(&css->sibling);

	if (ss) {
		/* css release path */
		if (!list_empty(&css->rstat_css_node)) {
			cgroup_rstat_flush(cgrp);
			list_del_rcu(&css->rstat_css_node);
		}

		cgroup_idr_replace(&ss->css_idr, NULL, css->id);
		if (ss->css_released)
			ss->css_released(css);
	} else {
		struct cgroup *tcgrp;

		/* cgroup release path */
		TRACE_CGROUP_PATH(release, cgrp);

		cgroup_rstat_flush(cgrp);

		spin_lock_irq(&css_set_lock);
		for (tcgrp = cgroup_parent(cgrp); tcgrp;
		     tcgrp = cgroup_parent(tcgrp))
			tcgrp->nr_dying_descendants--;
		spin_unlock_irq(&css_set_lock);

		/*
		 * There are two control paths which try to determine
		 * cgroup from dentry without going through kernfs -
		 * cgroupstats_build() and css_tryget_online_from_dir().
		 * Those are supported by RCU protecting clearing of
		 * cgrp->kn->priv backpointer.
		 */
		if (cgrp->kn)
			RCU_INIT_POINTER(*(void __rcu __force **)&cgrp->kn->priv,
					 NULL);
	}

	mutex_unlock(&cgroup_mutex);

	INIT_RCU_WORK(&css->destroy_rwork, css_free_rwork_fn);
	queue_rcu_work(cgroup_destroy_wq, &css->destroy_rwork);
}


	__releases(&cgroup_threadgroup_rwsem) __releases(&cgroup_mutex)
{
	cgroup_threadgroup_change_end(current);

	if (kargs->flags & CLONE_INTO_CGROUP) {
		struct cgroup *cgrp = kargs->cgrp;
		struct css_set *cset = kargs->cset;

		mutex_unlock(&cgroup_mutex);

		if (cset) {
			put_css_set(cset);
			kargs->cset = NULL;
		}

		if (cgrp) {
			cgroup_put(cgrp);
			kargs->cgrp = NULL;
		}
	}
}


struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset,
					 struct cgroup_subsys_state **dst_cssp)
{
	tset->cur_cset = list_first_entry(tset->csets, struct css_set, mg_node);
	tset->cur_task = NULL;

	return cgroup_taskset_next(tset, dst_cssp);
}


static bool cgroup_check_hierarchy_limits(struct cgroup *parent)
{
	struct cgroup *cgroup;
	int ret = false;
	int level = 1;

	lockdep_assert_held(&cgroup_mutex);

	for (cgroup = parent; cgroup; cgroup = cgroup_parent(cgroup)) {
		if (cgroup->nr_descendants >= cgroup->max_descendants)
			goto fail;

		if (level > cgroup->max_depth)
			goto fail;

		level++;
	}

	ret = true;
fail:
	return ret;
}


static void cgroup_print_ss_mask(struct seq_file *seq, u16 ss_mask)
{
	struct cgroup_subsys *ss;
	bool printed = false;
	int ssid;

	do_each_subsys_mask(ss, ssid, ss_mask) {
		if (printed)
			seq_putc(seq, ' ');
		seq_puts(seq, ss->name);
		printed = true;
	} while_each_subsys_mask();
	if (printed)
		seq_putc(seq, '\n');
}


static int cgroup_addrm_files(struct cgroup_subsys_state *css,
			      struct cgroup *cgrp, struct cftype cfts[],
			      bool is_add)
{
	struct cftype *cft, *cft_end = NULL;
	int ret = 0;

	lockdep_assert_held(&cgroup_mutex);

restart:
	for (cft = cfts; cft != cft_end && cft->name[0] != '\0'; cft++) {
		/* does cft->flags tell us to skip this file on @cgrp? */
		if ((cft->flags & CFTYPE_PRESSURE) && !cgroup_psi_enabled())
			continue;
		if ((cft->flags & __CFTYPE_ONLY_ON_DFL) && !cgroup_on_dfl(cgrp))
			continue;
		if ((cft->flags & __CFTYPE_NOT_ON_DFL) && cgroup_on_dfl(cgrp))
			continue;
		if ((cft->flags & CFTYPE_NOT_ON_ROOT) && !cgroup_parent(cgrp))
			continue;
		if ((cft->flags & CFTYPE_ONLY_ON_ROOT) && cgroup_parent(cgrp))
			continue;
		if ((cft->flags & CFTYPE_DEBUG) && !cgroup_debug)
			continue;
		if (is_add) {
			ret = cgroup_add_file(css, cgrp, cft);
			if (ret) {
				pr_warn("%s: failed to add %s, err=%d\n",
					__func__, cft->name, ret);
				cft_end = cft;
				is_add = false;
				goto restart;
			}
		} else {
			cgroup_rm_file(cgrp, cft);
		}
	}
	return ret;
}


static void cgroup_procs_release(struct kernfs_open_file *of)
{
	struct cgroup_file_ctx *ctx = of->priv;

	if (ctx->procs.started)
		css_task_iter_end(&ctx->procs.iter);
}


static ssize_t state_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	struct memory_block *mem = to_memory_block(dev);
	ssize_t len = 0;

	/*
	 * We can probably put these states in a nice little array
	 * so that they're not open-coded
	 */
	switch (mem->state) {
	case MEM_ONLINE:
		len = sysfs_emit(buf, "online\n");
		break;
	case MEM_OFFLINE:
		len = sysfs_emit(buf, "offline\n");
		break;
	case MEM_GOING_OFFLINE:
		len = sysfs_emit(buf, "going-offline\n");
		break;
	default:
		len = sysfs_emit(buf, "ERROR-UNKNOWN-%ld\n",
				 mem->state);
		WARN_ON(1);
		break;
	}

	return len;
}


static void __device_link_del(struct kref *kref)
{
	struct device_link *link = container_of(kref, struct device_link, kref);

	dev_dbg(link->consumer, "Dropping the link to %s\n",
		dev_name(link->supplier));

	if (link->flags & DL_FLAG_PM_RUNTIME)
		pm_runtime_drop_link(link->consumer);

	list_del_rcu(&link->s_node);
	list_del_rcu(&link->c_node);
	device_unregister(&link->link_dev);
}


static int soc_device_match_one(struct device *dev, void *arg)
{
	struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);

	return soc_device_match_attr(soc_dev->attr, arg);
}


static int __platform_get_irq_byname(struct platform_device *dev,
				     const char *name)
{
	struct resource *r;
	int ret;

	if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) {
		ret = of_irq_get_byname(dev->dev.of_node, name);
		if (ret > 0 || ret == -EPROBE_DEFER)
			return ret;
	}

	r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
	if (r) {
		WARN(r->start == 0, "0 is an invalid IRQ number\n");
		return r->start;
	}

	return -ENXIO;
}


struct device *device_find_child_by_name(struct device *parent,
					 const char *name)
{
	struct klist_iter i;
	struct device *child;

	if (!parent)
		return NULL;

	klist_iter_init(&parent->p->klist_children, &i);
	while ((child = next_device(&i)))
		if (!strcmp(dev_name(child), name) && get_device(child))
			break;
	klist_iter_exit(&i);
	return child;
}


static int deferred_devs_show(struct seq_file *s, void *data)
{
	struct device_private *curr;

	mutex_lock(&deferred_probe_mutex);

	list_for_each_entry(curr, &deferred_probe_pending_list, deferred_probe)
		seq_printf(s, "%s\t%s", dev_name(curr->device),
			   curr->device->p->deferred_probe_reason ?: "\n");

	mutex_unlock(&deferred_probe_mutex);

	return 0;
}


int device_attach(struct device *dev)
{
	return __device_attach(dev, false);
}


static ssize_t state_store(struct device *dev, struct device_attribute *attr,
			   const char *buf, size_t count)
{
	const int online_type = memhp_online_type_from_str(buf);
	struct memory_block *mem = to_memory_block(dev);
	int ret;

	if (online_type < 0)
		return -EINVAL;

	ret = lock_device_hotplug_sysfs();
	if (ret)
		return ret;

	switch (online_type) {
	case MMOP_ONLINE_KERNEL:
	case MMOP_ONLINE_MOVABLE:
	case MMOP_ONLINE:
		/* mem->online_type is protected by device_hotplug_lock */
		mem->online_type = online_type;
		ret = device_online(&mem->dev);
		break;
	case MMOP_OFFLINE:
		ret = device_offline(&mem->dev);
		break;
	default:
		ret = -EINVAL; /* should never happen */
	}

	unlock_device_hotplug();

	if (ret < 0)
		return ret;
	if (ret)
		return -EINVAL;

	return count;
}


static inline bool hugetlb_register_node(struct node *node)
{
	if (__hugetlb_register_node &&
			node_state(node->dev.id, N_MEMORY)) {
		__hugetlb_register_node(node);
		return true;
	}
	return false;
}


void device_link_del(struct device_link *link)
{
	device_links_write_lock();
	device_link_put_kref(link);
	device_links_write_unlock();
}


static void __device_links_no_driver(struct device *dev)
{
	struct device_link *link, *ln;

	list_for_each_entry_safe_reverse(link, ln, &dev->links.suppliers, c_node) {
		if (!(link->flags & DL_FLAG_MANAGED))
			continue;

		if (link->flags & DL_FLAG_AUTOREMOVE_CONSUMER) {
			device_link_drop_managed(link);
			continue;
		}

		if (link->status != DL_STATE_CONSUMER_PROBE &&
		    link->status != DL_STATE_ACTIVE)
			continue;

		if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
			WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
		} else {
			WARN_ON(!(link->flags & DL_FLAG_SYNC_STATE_ONLY));
			WRITE_ONCE(link->status, DL_STATE_DORMANT);
		}
	}

	dev->links.status = DL_DEV_NO_DRIVER;
}


static int cache_add_dev(unsigned int cpu)
{
	unsigned int i;
	int rc;
	struct device *ci_dev, *parent;
	struct cacheinfo *this_leaf;
	struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
	const struct attribute_group **cache_groups;

	rc = cpu_cache_sysfs_init(cpu);
	if (unlikely(rc < 0))
		return rc;

	parent = per_cpu_cache_dev(cpu);
	for (i = 0; i < cache_leaves(cpu); i++) {
		this_leaf = this_cpu_ci->info_list + i;
		if (this_leaf->disable_sysfs)
			continue;
		if (this_leaf->type == CACHE_TYPE_NOCACHE)
			break;
		cache_groups = cache_get_attribute_groups(this_leaf);
		ci_dev = cpu_device_create(parent, this_leaf, cache_groups,
					   "index%1u", i);
		if (IS_ERR(ci_dev)) {
			rc = PTR_ERR(ci_dev);
			goto err;
		}
		per_cache_index_dev(cpu, i) = ci_dev;
	}
	cpumask_set_cpu(cpu, &cache_dev_map);

	return 0;
err:
	cpu_cache_sysfs_exit(cpu);
	return rc;
}


ssize_t __weak cpu_show_meltdown(struct device *dev,
				 struct device_attribute *attr, char *buf)
{
	return sysfs_emit(buf, "Not affected\n");
}


void device_destroy(struct class *class, dev_t devt)
{
	struct device *dev;

	dev = class_find_device_by_devt(class, devt);
	if (dev) {
		put_device(dev);
		device_unregister(dev);
	}
}


void device_initial_probe(struct device *dev)
{
	__device_attach(dev, true);
}


int device_for_each_child(struct device *parent, void *data,
			  int (*fn)(struct device *dev, void *data))
{
	struct klist_iter i;
	struct device *child;
	int error = 0;

	if (!parent->p)
		return 0;

	klist_iter_init(&parent->p->klist_children, &i);
	while (!error && (child = next_device(&i)))
		error = fn(child, data);
	klist_iter_exit(&i);
	return error;
}


static inline struct kobject *get_glue_dir(struct device *dev)
{
	return dev->kobj.parent;
}


u32 fw_devlink_get_flags(void)
{
	return fw_devlink_flags;
}


static int __init register_cpufreq_notifier(void)
{
	int ret;

	/*
	 * on ACPI-based systems we need to use the default cpu capacity
	 * until we have the necessary code to parse the cpu capacity, so
	 * skip registering cpufreq notifier.
	 */
	if (!acpi_disabled || !raw_capacity)
		return -EINVAL;

	if (!alloc_cpumask_var(&cpus_to_visit, GFP_KERNEL))
		return -ENOMEM;

	cpumask_copy(cpus_to_visit, cpu_possible_mask);

	ret = cpufreq_register_notifier(&init_cpu_capacity_notifier,
					CPUFREQ_POLICY_NOTIFIER);

	if (ret)
		free_cpumask_var(cpus_to_visit);

	return ret;
}


static ssize_t wakeup_active_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{
	unsigned int active = 0;
	bool enabled = false;

	spin_lock_irq(&dev->power.lock);
	if (dev->power.wakeup) {
		active = dev->power.wakeup->active;
		enabled = true;
	}
	spin_unlock_irq(&dev->power.lock);
	return enabled ? sprintf(buf, "%u\n", active) : sprintf(buf, "\n");
}


void device_release_driver_internal(struct device *dev,
				    struct device_driver *drv,
				    struct device *parent)
{
	__device_driver_lock(dev, parent);

	if (!drv || drv == dev->driver)
		__device_release_driver(dev, parent);

	__device_driver_unlock(dev, parent);
}


static ssize_t total_time_ms_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
{
	struct wakeup_source *ws = dev_get_drvdata(dev);
	ktime_t active_time;
	ktime_t total_time = ws->total_time;

	if (ws->active) {
		active_time = ktime_sub(ktime_get(), ws->last_time);
		total_time = ktime_add(total_time, active_time);
	}
	return sysfs_emit(buf, "%lld\n", ktime_to_ms(total_time));
}


void __iomem *devm_platform_ioremap_resource(struct platform_device *pdev,
					     unsigned int index)
{
	return devm_platform_get_and_ioremap_resource(pdev, index, NULL);
}


static void device_remove_sys_dev_entry(struct device *dev)
{
	struct kobject *kobj = device_to_dev_kobj(dev);
	char devt_str[15];

	if (kobj) {
		format_dev_t(devt_str, dev->devt);
		sysfs_remove_link(kobj, devt_str);
	}
}


static int __init devlink_class_init(void)
{
	int ret;

	ret = class_register(&devlink_class);
	if (ret)
		return ret;

	ret = class_interface_register(&devlink_class_intf);
	if (ret)
		class_unregister(&devlink_class);

	return ret;
}


ssize_t device_store_int(struct device *dev,
			 struct device_attribute *attr,
			 const char *buf, size_t size)
{
	struct dev_ext_attribute *ea = to_ext_attr(attr);
	int ret;
	long new;

	ret = kstrtol(buf, 0, &new);
	if (ret)
		return ret;

	if (new > INT_MAX || new < INT_MIN)
		return -EINVAL;
	*(int *)(ea->var) = new;
	/* Always return full write size even if we didn't consume all */
	return size;
}


bool device_links_busy(struct device *dev)
{
	struct device_link *link;
	bool ret = false;

	device_links_write_lock();

	list_for_each_entry(link, &dev->links.consumers, s_node) {
		if (!(link->flags & DL_FLAG_MANAGED))
			continue;

		if (link->status == DL_STATE_CONSUMER_PROBE
		    || link->status == DL_STATE_ACTIVE) {
			ret = true;
			break;
		}
		WRITE_ONCE(link->status, DL_STATE_SUPPLIER_UNBIND);
	}

	dev->links.status = DL_DEV_UNBINDING;

	device_links_write_unlock();
	return ret;
}


static void driver_sysfs_remove(struct device *dev)
{
	struct device_driver *drv = dev->driver;

	if (drv) {
		if (drv->coredump)
			device_remove_file(dev, &dev_attr_coredump);
		sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));
		sysfs_remove_link(&dev->kobj, "driver");
	}
}