tcp_input(struct mbuf *m, int iphlen, struct socket *inso)

{

  	struct ip save_ip, *ip;

	register struct tcpiphdr *ti;

	caddr_t optp = NULL;

	int optlen = 0;

	int len, tlen, off;

        register struct tcpcb *tp = NULL;

	register int tiflags;

        struct socket *so = NULL;

	int todrop, acked, ourfinisacked, needoutput = 0;

	int iss = 0;

	u_long tiwin;

	int ret;

    struct ex_list *ex_ptr;

    Slirp *slirp;

	DEBUG_CALL("tcp_input");

	DEBUG_ARGS((dfd, " m = %8lx  iphlen = %2d  inso = %lx\n",

		    (long )m, iphlen, (long )inso ));

	/*

	 * If called with m == 0, then we're continuing the connect

	 */

	if (m == NULL) {

		so = inso;

		slirp = so->slirp;

		/* Re-set a few variables */

		tp = sototcpcb(so);

		m = so->so_m;

                so->so_m = NULL;

		ti = so->so_ti;

		tiwin = ti->ti_win;

		tiflags = ti->ti_flags;

		goto cont_conn;

	}

	slirp = m->slirp;

	/*

	 * Get IP and TCP header together in first mbuf.

	 * Note: IP leaves IP header in first mbuf.

	 */

	ti = mtod(m, struct tcpiphdr *);

	if (iphlen > sizeof(struct ip )) {

	  ip_stripoptions(m, (struct mbuf *)0);

	  iphlen=sizeof(struct ip );

	}

	/* XXX Check if too short */

	/*

	 * Save a copy of the IP header in case we want restore it

	 * for sending an ICMP error message in response.

	 */

	ip=mtod(m, struct ip *);

	save_ip = *ip;

	save_ip.ip_len+= iphlen;

	/*

	 * Checksum extended TCP header and data.

	 */

	tlen = ((struct ip *)ti)->ip_len;

        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;

        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));

	ti->ti_x1 = 0;

	ti->ti_len = htons((uint16_t)tlen);

	len = sizeof(struct ip ) + tlen;

	if(cksum(m, len)) {

	  goto drop;

	}

	/*

	 * Check that TCP offset makes sense,

	 * pull out TCP options and adjust length.		XXX

	 */

	off = ti->ti_off << 2;

	if (off < sizeof (struct tcphdr) || off > tlen) {

	  goto drop;

	}

	tlen -= off;

	ti->ti_len = tlen;

	if (off > sizeof (struct tcphdr)) {

	  optlen = off - sizeof (struct tcphdr);

	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);

	}

	tiflags = ti->ti_flags;

	/*

	 * Convert TCP protocol specific fields to host format.

	 */

	NTOHL(ti->ti_seq);

	NTOHL(ti->ti_ack);

	NTOHS(ti->ti_win);

	NTOHS(ti->ti_urp);

	/*

	 * Drop TCP, IP headers and TCP options.

	 */

	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

    if (slirp->restricted) {

        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {

            if (ex_ptr->ex_fport == ti->ti_dport &&

                ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {

                break;

            }

        }

        if (!ex_ptr)

            goto drop;

    }

	/*

	 * Locate pcb for segment.

	 */

findso:

	so = slirp->tcp_last_so;

	if (so->so_fport != ti->ti_dport ||

	    so->so_lport != ti->ti_sport ||

	    so->so_laddr.s_addr != ti->ti_src.s_addr ||

	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {

		so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,

			       ti->ti_dst, ti->ti_dport);

		if (so)

			slirp->tcp_last_so = so;

	}

	/*

	 * If the state is CLOSED (i.e., TCB does not exist) then

	 * all data in the incoming segment is discarded.

	 * If the TCB exists but is in CLOSED state, it is embryonic,

	 * but should either do a listen or a connect soon.

	 *

	 * state == CLOSED means we've done socreate() but haven't

	 * attached it to a protocol yet...

	 *

	 * XXX If a TCB does not exist, and the TH_SYN flag is

	 * the only flag set, then create a session, mark it

	 * as if it was LISTENING, and continue...

	 */

        if (so == NULL) {

	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)

	    goto dropwithreset;

	  if ((so = socreate(slirp)) == NULL)

	    goto dropwithreset;

	  if (tcp_attach(so) < 0) {

	    free(so); /* Not sofree (if it failed, it's not insqued) */

	    goto dropwithreset;

	  }

	  sbreserve(&so->so_snd, TCP_SNDSPACE);

	  sbreserve(&so->so_rcv, TCP_RCVSPACE);

	  so->so_laddr = ti->ti_src;

	  so->so_lport = ti->ti_sport;

	  so->so_faddr = ti->ti_dst;

	  so->so_fport = ti->ti_dport;

	  if ((so->so_iptos = tcp_tos(so)) == 0)

	    so->so_iptos = ((struct ip *)ti)->ip_tos;

	  tp = sototcpcb(so);

	  tp->t_state = TCPS_LISTEN;

	}

        /*

         * If this is a still-connecting socket, this probably

         * a retransmit of the SYN.  Whether it's a retransmit SYN

	 * or something else, we nuke it.

         */

        if (so->so_state & SS_ISFCONNECTING)

                goto drop;

	tp = sototcpcb(so);

	/* XXX Should never fail */

        if (tp == NULL)

		goto dropwithreset;

	if (tp->t_state == TCPS_CLOSED)

		goto drop;

	tiwin = ti->ti_win;

	/*

	 * Segment received on connection.

	 * Reset idle time and keep-alive timer.

	 */

	tp->t_idle = 0;

	if (SO_OPTIONS)

	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;

	else

	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;

	/*

	 * Process options if not in LISTEN state,

	 * else do it below (after getting remote address).

	 */

	if (optp && tp->t_state != TCPS_LISTEN)

		tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	/*

	 * Header prediction: check for the two common cases

	 * of a uni-directional data xfer.  If the packet has

	 * no control flags, is in-sequence, the window didn't

	 * change and we're not retransmitting, it's a

	 * candidate.  If the length is zero and the ack moved

	 * forward, we're the sender side of the xfer.  Just

	 * free the data acked & wake any higher level process

	 * that was blocked waiting for space.  If the length

	 * is non-zero and the ack didn't move, we're the

	 * receiver side.  If we're getting packets in-order

	 * (the reassembly queue is empty), add the data to

	 * the socket buffer and note that we need a delayed ack.

	 *

	 * XXX Some of these tests are not needed

	 * eg: the tiwin == tp->snd_wnd prevents many more

	 * predictions.. with no *real* advantage..

	 */

	if (tp->t_state == TCPS_ESTABLISHED &&

	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&

	    ti->ti_seq == tp->rcv_nxt &&

	    tiwin && tiwin == tp->snd_wnd &&

	    tp->snd_nxt == tp->snd_max) {

		if (ti->ti_len == 0) {

			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&

			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&

			    tp->snd_cwnd >= tp->snd_wnd) {

				/*

				 * this is a pure ack for outstanding data.

				 */

				if (tp->t_rtt &&

				    SEQ_GT(ti->ti_ack, tp->t_rtseq))

					tcp_xmit_timer(tp, tp->t_rtt);

				acked = ti->ti_ack - tp->snd_una;

				sbdrop(&so->so_snd, acked);

				tp->snd_una = ti->ti_ack;

				m_free(m);

				/*

				 * If all outstanding data are acked, stop

				 * retransmit timer, otherwise restart timer

				 * using current (possibly backed-off) value.

				 * If process is waiting for space,

				 * wakeup/selwakeup/signal.  If data

				 * are ready to send, let tcp_output

				 * decide between more output or persist.

				 */

				if (tp->snd_una == tp->snd_max)

					tp->t_timer[TCPT_REXMT] = 0;

				else if (tp->t_timer[TCPT_PERSIST] == 0)

					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

				/*

				 * This is called because sowwakeup might have

				 * put data into so_snd.  Since we don't so sowwakeup,

				 * we don't need this.. XXX???

				 */

				if (so->so_snd.sb_cc)

					(void) tcp_output(tp);

				return;

			}

		} else if (ti->ti_ack == tp->snd_una &&

		    tcpfrag_list_empty(tp) &&

		    ti->ti_len <= sbspace(&so->so_rcv)) {

			/*

			 * this is a pure, in-sequence data packet

			 * with nothing on the reassembly queue and

			 * we have enough buffer space to take it.

			 */

			tp->rcv_nxt += ti->ti_len;

			/*

			 * Add data to socket buffer.

			 */

			if (so->so_emu) {

				if (tcp_emu(so,m)) sbappend(so, m);

			} else

				sbappend(so, m);

			/*

			 * If this is a short packet, then ACK now - with Nagel

			 *	congestion avoidance sender won't send more until

			 *	he gets an ACK.

			 *

			 * It is better to not delay acks at all to maximize

			 * TCP throughput.  See RFC 2581.

			 */

			tp->t_flags |= TF_ACKNOW;

			tcp_output(tp);

			return;

		}

	} /* header prediction */

	/*

	 * Calculate amount of space in receive window,

	 * and then do TCP input processing.

	 * Receive window is amount of space in rcv queue,

	 * but not less than advertised window.

	 */

	{ int win;

          win = sbspace(&so->so_rcv);

	  if (win < 0)

	    win = 0;

	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));

	}

	switch (tp->t_state) {

	/*

	 * If the state is LISTEN then ignore segment if it contains an RST.

	 * If the segment contains an ACK then it is bad and send a RST.

	 * If it does not contain a SYN then it is not interesting; drop it.

	 * Don't bother responding if the destination was a broadcast.

	 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial

	 * tp->iss, and send a segment:

	 *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>

	 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.

	 * Fill in remote peer address fields if not previously specified.

	 * Enter SYN_RECEIVED state, and process any other fields of this

	 * segment in this state.

	 */

	case TCPS_LISTEN: {

	  if (tiflags & TH_RST)

	    goto drop;

	  if (tiflags & TH_ACK)

	    goto dropwithreset;

	  if ((tiflags & TH_SYN) == 0)

	    goto drop;

	  /*

	   * This has way too many gotos...

	   * But a bit of spaghetti code never hurt anybody :)

	   */

	  /*

	   * If this is destined for the control address, then flag to

	   * tcp_ctl once connected, otherwise connect

	   */

	  if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==

	      slirp->vnetwork_addr.s_addr) {

	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&

		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {

		/* May be an add exec */

		for (ex_ptr = slirp->exec_list; ex_ptr;

		     ex_ptr = ex_ptr->ex_next) {

		  if(ex_ptr->ex_fport == so->so_fport &&

		     so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {

		    so->so_state |= SS_CTL;

		    break;

		  }

		}

		if (so->so_state & SS_CTL) {

		    goto cont_input;

		}

	    }

	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */

	  }

	  if (so->so_emu & EMU_NOCONNECT) {

	    so->so_emu &= ~EMU_NOCONNECT;

	    goto cont_input;

	  }

	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {

	    u_char code=ICMP_UNREACH_NET;

	    DEBUG_MISC((dfd, " tcp fconnect errno = %d-%s\n",

			errno,strerror(errno)));

	    if(errno == ECONNREFUSED) {

	      /* ACK the SYN, send RST to refuse the connection */

	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,

			  TH_RST|TH_ACK);

	    } else {

	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;

	      HTONL(ti->ti_seq);             /* restore tcp header */

	      HTONL(ti->ti_ack);

	      HTONS(ti->ti_win);

	      HTONS(ti->ti_urp);

	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

	      *ip=save_ip;

	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));

	    }

            tcp_close(tp);

	    m_free(m);

	  } else {

	    /*

	     * Haven't connected yet, save the current mbuf

	     * and ti, and return

	     * XXX Some OS's don't tell us whether the connect()

	     * succeeded or not.  So we must time it out.

	     */

	    so->so_m = m;

	    so->so_ti = ti;

	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;

	    tp->t_state = TCPS_SYN_RECEIVED;

	    tcp_template(tp);

	  }

	  return;

	cont_conn:

	  /* m==NULL

	   * Check if the connect succeeded

	   */

	  if (so->so_state & SS_NOFDREF) {

	    tp = tcp_close(tp);

	    goto dropwithreset;

	  }

	cont_input:

	  tcp_template(tp);

	  if (optp)

	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	  if (iss)

	    tp->iss = iss;

	  else

	    tp->iss = slirp->tcp_iss;

	  slirp->tcp_iss += TCP_ISSINCR/2;

	  tp->irs = ti->ti_seq;

	  tcp_sendseqinit(tp);

	  tcp_rcvseqinit(tp);

	  tp->t_flags |= TF_ACKNOW;

	  tp->t_state = TCPS_SYN_RECEIVED;

	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;

	  goto trimthenstep6;

	} /* case TCPS_LISTEN */

	/*

	 * If the state is SYN_SENT:

	 *	if seg contains an ACK, but not for our SYN, drop the input.

	 *	if seg contains a RST, then drop the connection.

	 *	if seg does not contain SYN, then drop it.

	 * Otherwise this is an acceptable SYN segment

	 *	initialize tp->rcv_nxt and tp->irs

	 *	if seg contains ack then advance tp->snd_una

	 *	if SYN has been acked change to ESTABLISHED else SYN_RCVD state

	 *	arrange for segment to be acked (eventually)

	 *	continue processing rest of data/controls, beginning with URG

	 */

	case TCPS_SYN_SENT:

		if ((tiflags & TH_ACK) &&

		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||

		     SEQ_GT(ti->ti_ack, tp->snd_max)))

			goto dropwithreset;

		if (tiflags & TH_RST) {

                        if (tiflags & TH_ACK) {

                                tcp_drop(tp, 0); /* XXX Check t_softerror! */

                        }

			goto drop;

		}

		if ((tiflags & TH_SYN) == 0)

			goto drop;

		if (tiflags & TH_ACK) {

			tp->snd_una = ti->ti_ack;

			if (SEQ_LT(tp->snd_nxt, tp->snd_una))

				tp->snd_nxt = tp->snd_una;

		}

		tp->t_timer[TCPT_REXMT] = 0;

		tp->irs = ti->ti_seq;

		tcp_rcvseqinit(tp);

		tp->t_flags |= TF_ACKNOW;

		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {

			soisfconnected(so);

			tp->t_state = TCPS_ESTABLISHED;

			(void) tcp_reass(tp, (struct tcpiphdr *)0,

				(struct mbuf *)0);

			/*

			 * if we didn't have to retransmit the SYN,

			 * use its rtt as our initial srtt & rtt var.

			 */

			if (tp->t_rtt)

				tcp_xmit_timer(tp, tp->t_rtt);

		} else

			tp->t_state = TCPS_SYN_RECEIVED;

trimthenstep6:

		/*

		 * Advance ti->ti_seq to correspond to first data byte.

		 * If data, trim to stay within window,

		 * dropping FIN if necessary.

		 */

		ti->ti_seq++;

		if (ti->ti_len > tp->rcv_wnd) {

			todrop = ti->ti_len - tp->rcv_wnd;

			m_adj(m, -todrop);

			ti->ti_len = tp->rcv_wnd;

			tiflags &= ~TH_FIN;

		}

		tp->snd_wl1 = ti->ti_seq - 1;

		tp->rcv_up = ti->ti_seq;

		goto step6;

	} /* switch tp->t_state */

	/*

	 * States other than LISTEN or SYN_SENT.

	 * Check that at least some bytes of segment are within

	 * receive window.  If segment begins before rcv_nxt,

	 * drop leading data (and SYN); if nothing left, just ack.

	 */

	todrop = tp->rcv_nxt - ti->ti_seq;

	if (todrop > 0) {

		if (tiflags & TH_SYN) {

			tiflags &= ~TH_SYN;

			ti->ti_seq++;

			if (ti->ti_urp > 1)

				ti->ti_urp--;

			else

				tiflags &= ~TH_URG;

			todrop--;

		}

		/*

		 * Following if statement from Stevens, vol. 2, p. 960.

		 */

		if (todrop > ti->ti_len

		    || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {

			/*

			 * Any valid FIN must be to the left of the window.

			 * At this point the FIN must be a duplicate or out

			 * of sequence; drop it.

			 */

			tiflags &= ~TH_FIN;

			/*

			 * Send an ACK to resynchronize and drop any data.

			 * But keep on processing for RST or ACK.

			 */

			tp->t_flags |= TF_ACKNOW;

			todrop = ti->ti_len;

		}

		m_adj(m, todrop);

		ti->ti_seq += todrop;

		ti->ti_len -= todrop;

		if (ti->ti_urp > todrop)

			ti->ti_urp -= todrop;

		else {

			tiflags &= ~TH_URG;

			ti->ti_urp = 0;

		}

	}

	/*

	 * If new data are received on a connection after the

	 * user processes are gone, then RST the other end.

	 */

	if ((so->so_state & SS_NOFDREF) &&

	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {

		tp = tcp_close(tp);

		goto dropwithreset;

	}

	/*

	 * If segment ends after window, drop trailing data

	 * (and PUSH and FIN); if nothing left, just ACK.

	 */

	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);

	if (todrop > 0) {

		if (todrop >= ti->ti_len) {

			/*

			 * If a new connection request is received

			 * while in TIME_WAIT, drop the old connection

			 * and start over if the sequence numbers

			 * are above the previous ones.

			 */

			if (tiflags & TH_SYN &&

			    tp->t_state == TCPS_TIME_WAIT &&

			    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {

				iss = tp->rcv_nxt + TCP_ISSINCR;

				tp = tcp_close(tp);

				goto findso;

			}

			/*

			 * If window is closed can only take segments at

			 * window edge, and have to drop data and PUSH from

			 * incoming segments.  Continue processing, but

			 * remember to ack.  Otherwise, drop segment

			 * and ack.

			 */

			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {

				tp->t_flags |= TF_ACKNOW;

			} else {

				goto dropafterack;

			}

		}

		m_adj(m, -todrop);

		ti->ti_len -= todrop;

		tiflags &= ~(TH_PUSH|TH_FIN);

	}

	/*

	 * If the RST bit is set examine the state:

	 *    SYN_RECEIVED STATE:

	 *	If passive open, return to LISTEN state.

	 *	If active open, inform user that connection was refused.

	 *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:

	 *	Inform user that connection was reset, and close tcb.

	 *    CLOSING, LAST_ACK, TIME_WAIT STATES

	 *	Close the tcb.

	 */

	if (tiflags&TH_RST) switch (tp->t_state) {

	case TCPS_SYN_RECEIVED:

	case TCPS_ESTABLISHED:

	case TCPS_FIN_WAIT_1:

	case TCPS_FIN_WAIT_2:

	case TCPS_CLOSE_WAIT:

		tp->t_state = TCPS_CLOSED;

                tcp_close(tp);

		goto drop;

	case TCPS_CLOSING:

	case TCPS_LAST_ACK:

	case TCPS_TIME_WAIT:

                tcp_close(tp);

		goto drop;

	}

	/*

	 * If a SYN is in the window, then this is an

	 * error and we send an RST and drop the connection.

	 */

	if (tiflags & TH_SYN) {

		tp = tcp_drop(tp,0);

		goto dropwithreset;

	}

	/*

	 * If the ACK bit is off we drop the segment and return.

	 */

	if ((tiflags & TH_ACK) == 0) goto drop;

	/*

	 * Ack processing.

	 */

	switch (tp->t_state) {

	/*

	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter

	 * ESTABLISHED state and continue processing, otherwise

	 * send an RST.  una<=ack<=max

	 */

	case TCPS_SYN_RECEIVED:

		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||

		    SEQ_GT(ti->ti_ack, tp->snd_max))

			goto dropwithreset;

		tp->t_state = TCPS_ESTABLISHED;

		/*

		 * The sent SYN is ack'ed with our sequence number +1

		 * The first data byte already in the buffer will get

		 * lost if no correction is made.  This is only needed for

		 * SS_CTL since the buffer is empty otherwise.

		 * tp->snd_una++; or:

		 */

		tp->snd_una=ti->ti_ack;

		if (so->so_state & SS_CTL) {

		  /* So tcp_ctl reports the right state */

		  ret = tcp_ctl(so);

		  if (ret == 1) {

		    soisfconnected(so);

		    so->so_state &= ~SS_CTL;   /* success XXX */

		  } else if (ret == 2) {

		    so->so_state &= SS_PERSISTENT_MASK;

		    so->so_state |= SS_NOFDREF; /* CTL_CMD */

		  } else {

		    needoutput = 1;

		    tp->t_state = TCPS_FIN_WAIT_1;

		  }

		} else {

		  soisfconnected(so);

		}

		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);

		tp->snd_wl1 = ti->ti_seq - 1;

		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */

		goto synrx_to_est;

		/* fall into ... */

	/*

	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range

	 * ACKs.  If the ack is in the range

	 *	tp->snd_una < ti->ti_ack <= tp->snd_max

	 * then advance tp->snd_una to ti->ti_ack and drop

	 * data from the retransmission queue.  If this ACK reflects

	 * more up to date window information we update our window information.

	 */

	case TCPS_ESTABLISHED:

	case TCPS_FIN_WAIT_1:

	case TCPS_FIN_WAIT_2:

	case TCPS_CLOSE_WAIT:

	case TCPS_CLOSING:

	case TCPS_LAST_ACK:

	case TCPS_TIME_WAIT:

		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {

			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {

			  DEBUG_MISC((dfd, " dup ack  m = %lx  so = %lx\n",

				      (long )m, (long )so));

				/*

				 * If we have outstanding data (other than

				 * a window probe), this is a completely

				 * duplicate ack (ie, window info didn't

				 * change), the ack is the biggest we've

				 * seen and we've seen exactly our rexmt

				 * threshold of them, assume a packet

				 * has been dropped and retransmit it.

				 * Kludge snd_nxt & the congestion

				 * window so we send only this one

				 * packet.

				 *

				 * We know we're losing at the current

				 * window size so do congestion avoidance

				 * (set ssthresh to half the current window

				 * and pull our congestion window back to

				 * the new ssthresh).

				 *

				 * Dup acks mean that packets have left the

				 * network (they're now cached at the receiver)

				 * so bump cwnd by the amount in the receiver

				 * to keep a constant cwnd packets in the

				 * network.

				 */

				if (tp->t_timer[TCPT_REXMT] == 0 ||

				    ti->ti_ack != tp->snd_una)

					tp->t_dupacks = 0;

				else if (++tp->t_dupacks == TCPREXMTTHRESH) {

					tcp_seq onxt = tp->snd_nxt;

					u_int win =

					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /

						tp->t_maxseg;

					if (win < 2)

						win = 2;

					tp->snd_ssthresh = win * tp->t_maxseg;

					tp->t_timer[TCPT_REXMT] = 0;

					tp->t_rtt = 0;

					tp->snd_nxt = ti->ti_ack;

					tp->snd_cwnd = tp->t_maxseg;

					(void) tcp_output(tp);

					tp->snd_cwnd = tp->snd_ssthresh +

					       tp->t_maxseg * tp->t_dupacks;

					if (SEQ_GT(onxt, tp->snd_nxt))

						tp->snd_nxt = onxt;

					goto drop;

				} else if (tp->t_dupacks > TCPREXMTTHRESH) {

					tp->snd_cwnd += tp->t_maxseg;

					(void) tcp_output(tp);

					goto drop;

				}

			} else

				tp->t_dupacks = 0;

			break;

		}

	synrx_to_est:

		/*

		 * If the congestion window was inflated to account

		 * for the other side's cached packets, retract it.

		 */

		if (tp->t_dupacks > TCPREXMTTHRESH &&

		    tp->snd_cwnd > tp->snd_ssthresh)

			tp->snd_cwnd = tp->snd_ssthresh;

		tp->t_dupacks = 0;

		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {

			goto dropafterack;

		}

		acked = ti->ti_ack - tp->snd_una;

		/*

		 * If transmit timer is running and timed sequence

		 * number was acked, update smoothed round trip time.

		 * Since we now have an rtt measurement, cancel the

		 * timer backoff (cf., Phil Karn's retransmit alg.).

		 * Recompute the initial retransmit timer.

		 */

		if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))

			tcp_xmit_timer(tp,tp->t_rtt);

		/*

		 * If all outstanding data is acked, stop retransmit

		 * timer and remember to restart (more output or persist).

		 * If there is more data to be acked, restart retransmit

		 * timer, using current (possibly backed-off) value.

		 */

		if (ti->ti_ack == tp->snd_max) {

			tp->t_timer[TCPT_REXMT] = 0;

			needoutput = 1;

		} else if (tp->t_timer[TCPT_PERSIST] == 0)

			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

		/*

		 * When new data is acked, open the congestion window.

		 * If the window gives us less than ssthresh packets

		 * in flight, open exponentially (maxseg per packet).

		 * Otherwise open linearly: maxseg per window

		 * (maxseg^2 / cwnd per packet).

		 */

		{

		  register u_int cw = tp->snd_cwnd;

		  register u_int incr = tp->t_maxseg;

		  if (cw > tp->snd_ssthresh)

		    incr = incr * incr / cw;

		  tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);

		}

		if (acked > so->so_snd.sb_cc) {

			tp->snd_wnd -= so->so_snd.sb_cc;

			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);

			ourfinisacked = 1;

		} else {

			sbdrop(&so->so_snd, acked);

			tp->snd_wnd -= acked;

			ourfinisacked = 0;

		}

		tp->snd_una = ti->ti_ack;

		if (SEQ_LT(tp->snd_nxt, tp->snd_una))

			tp->snd_nxt = tp->snd_una;

		switch (tp->t_state) {

		/*

		 * In FIN_WAIT_1 STATE in addition to the processing

		 * for the ESTABLISHED state if our FIN is now acknowledged

		 * then enter FIN_WAIT_2.

		 */

		case TCPS_FIN_WAIT_1:

			if (ourfinisacked) {

				/*

				 * If we can't receive any more

				 * data, then closing user can proceed.

				 * Starting the timer is contrary to the

				 * specification, but if we don't get a FIN

				 * we'll hang forever.

				 */

				if (so->so_state & SS_FCANTRCVMORE) {

					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;

				}

				tp->t_state = TCPS_FIN_WAIT_2;

			}

			break;

	 	/*

		 * In CLOSING STATE in addition to the processing for

		 * the ESTABLISHED state if the ACK acknowledges our FIN

		 * then enter the TIME-WAIT state, otherwise ignore

		 * the segment.

		 */

		case TCPS_CLOSING:

			if (ourfinisacked) {

				tp->t_state = TCPS_TIME_WAIT;

				tcp_canceltimers(tp);

				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;

			}

			break;

		/*

		 * In LAST_ACK, we may still be waiting for data to drain

		 * and/or to be acked, as well as for the ack of our FIN.

		 * If our FIN is now acknowledged, delete the TCB,

		 * enter the closed state and return.

		 */

		case TCPS_LAST_ACK:

			if (ourfinisacked) {

                                tcp_close(tp);

				goto drop;

			}

			break;

		/*

		 * In TIME_WAIT state the only thing that should arrive

		 * is a retransmission of the remote FIN.  Acknowledge

		 * it and restart the finack timer.

		 */

		case TCPS_TIME_WAIT:

			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;

			goto dropafterack;

		}

	} /* switch(tp->t_state) */

step6:

	/*

	 * Update window information.

	 * Don't look at window if no ACK: TAC's send garbage on first SYN.

	 */

	if ((tiflags & TH_ACK) &&

	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||

	    (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||

	    (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {

		tp->snd_wnd = tiwin;

		tp->snd_wl1 = ti->ti_seq;

		tp->snd_wl2 = ti->ti_ack;

		if (tp->snd_wnd > tp->max_sndwnd)

			tp->max_sndwnd = tp->snd_wnd;

		needoutput = 1;

	}

	/*

	 * Process segments with URG.

	 */

	if ((tiflags & TH_URG) && ti->ti_urp &&

	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {

		/*

		 * This is a kludge, but if we receive and accept

		 * random urgent pointers, we'll crash in

		 * soreceive.  It's hard to imagine someone

		 * actually wanting to send this much urgent data.

		 */

		if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {

			ti->ti_urp = 0;

			tiflags &= ~TH_URG;

			goto dodata;

		}

		/*

		 * If this segment advances the known urgent pointer,

		 * then mark the data stream.  This should not happen

		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since

		 * a FIN has been received from the remote side.

		 * In these states we ignore the URG.

		 *

		 * According to RFC961 (Assigned Protocols),

		 * the urgent pointer points to the last octet

		 * of urgent data.  We continue, however,

		 * to consider it to indicate the first octet

		 * of data past the urgent section as the original

		 * spec states (in one of two places).

		 */

		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {

			tp->rcv_up = ti->ti_seq + ti->ti_urp;

			so->so_urgc =  so->so_rcv.sb_cc +

				(tp->rcv_up - tp->rcv_nxt); /* -1; */

			tp->rcv_up = ti->ti_seq + ti->ti_urp;

		}

	} else

		/*

		 * If no out of band data is expected,

		 * pull receive urgent pointer along

		 * with the receive window.

		 */

		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))

			tp->rcv_up = tp->rcv_nxt;

dodata:

	/*

	 * If this is a small packet, then ACK now - with Nagel

	 *      congestion avoidance sender won't send more until

	 *      he gets an ACK.

	 */

	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&

	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {

		tp->t_flags |= TF_ACKNOW;

	}

	/*

	 * Process the segment text, merging it into the TCP sequencing queue,

	 * and arranging for acknowledgment of receipt if necessary.

	 * This process logically involves adjusting tp->rcv_wnd as data

	 * is presented to the user (this happens in tcp_usrreq.c,

	 * case PRU_RCVD).  If a FIN has already been received on this

	 * connection then we just ignore the text.

	 */

	if ((ti->ti_len || (tiflags&TH_FIN)) &&

	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {

		TCP_REASS(tp, ti, m, so, tiflags);

	} else {

		m_free(m);

		tiflags &= ~TH_FIN;

	}

	/*

	 * If FIN is received ACK the FIN and let the user know

	 * that the connection is closing.

	 */

	if (tiflags & TH_FIN) {

		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {

			/*

			 * If we receive a FIN we can't send more data,

			 * set it SS_FDRAIN

                         * Shutdown the socket if there is no rx data in the

			 * buffer.

			 * soread() is called on completion of shutdown() and

			 * will got to TCPS_LAST_ACK, and use tcp_output()

			 * to send the FIN.

			 */

			sofwdrain(so);

			tp->t_flags |= TF_ACKNOW;

			tp->rcv_nxt++;

		}

		switch (tp->t_state) {

	 	/*

		 * In SYN_RECEIVED and ESTABLISHED STATES

		 * enter the CLOSE_WAIT state.

		 */

		case TCPS_SYN_RECEIVED:

		case TCPS_ESTABLISHED:

		  if(so->so_emu == EMU_CTL)        /* no shutdown on socket */

		    tp->t_state = TCPS_LAST_ACK;

		  else

		    tp->t_state = TCPS_CLOSE_WAIT;

		  break;

	 	/*

		 * If still in FIN_WAIT_1 STATE FIN has not been acked so

		 * enter the CLOSING state.

		 */

		case TCPS_FIN_WAIT_1:

			tp->t_state = TCPS_CLOSING;

			break;

	 	/*

		 * In FIN_WAIT_2 state enter the TIME_WAIT state,

		 * starting the time-wait timer, turning off the other

		 * standard timers.

		 */

		case TCPS_FIN_WAIT_2:

			tp->t_state = TCPS_TIME_WAIT;

			tcp_canceltimers(tp);

			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;

			break;

		/*

		 * In TIME_WAIT state restart the 2 MSL time_wait timer.

		 */

		case TCPS_TIME_WAIT:

			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;

			break;

		}

	}

	/*

	 * Return any desired output.

	 */

	if (needoutput || (tp->t_flags & TF_ACKNOW)) {

		(void) tcp_output(tp);

	}

	return;

dropafterack:

	/*

	 * Generate an ACK dropping incoming segment if it occupies

	 * sequence space, where the ACK reflects our state.

	 */

	if (tiflags & TH_RST)

		goto drop;

	m_free(m);

	tp->t_flags |= TF_ACKNOW;

	(void) tcp_output(tp);

	return;

dropwithreset:

	/* reuses m if m!=NULL, m_free() unnecessary */

	if (tiflags & TH_ACK)

		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);

	else {

		if (tiflags & TH_SYN) ti->ti_len++;

		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,

		    TH_RST|TH_ACK);

	}

	return;

drop:

	/*

	 * Drop space held by incoming segment and return.

	 */

	m_free(m);

}


static bool cmd_identify(IDEState *s, uint8_t cmd)

{

    if (s->bs && s->drive_kind != IDE_CD) {

        if (s->drive_kind != IDE_CFATA) {

            ide_identify(s);

        } else {

            ide_cfata_identify(s);

        }

        s->status = READY_STAT | SEEK_STAT;

        ide_transfer_start(s, s->io_buffer, 512, ide_transfer_stop);

        ide_set_irq(s->bus);

        return false;

    } else {

        if (s->drive_kind == IDE_CD) {

            ide_set_signature(s);

        }

        ide_abort_command(s);

    }

    return true;

}


static coroutine_fn int dmg_co_read(BlockDriverState *bs, int64_t sector_num,

                                    uint8_t *buf, int nb_sectors)

{

    int ret;

    BDRVDMGState *s = bs->opaque;

    qemu_co_mutex_lock(&s->lock);

    ret = dmg_read(bs, sector_num, buf, nb_sectors);

    qemu_co_mutex_unlock(&s->lock);

    return ret;

}


static void cmd_read_cdvd_capacity(IDEState *s, uint8_t* buf)

{

    uint64_t total_sectors = s->nb_sectors >> 2;

    if (total_sectors == 0) {

        ide_atapi_cmd_error(s, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT);

        return;

    }

    /* NOTE: it is really the number of sectors minus 1 */

    cpu_to_ube32(buf, total_sectors - 1);

    cpu_to_ube32(buf + 4, 2048);

    ide_atapi_cmd_reply(s, 8, 8);

}


int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM )

{

    flag aSign;

    int16 aExp, shiftCount;

    bits32 aSig;

    bits64 aSig64;

    int64 z;

    aSig = extractFloat32Frac( a );

    aExp = extractFloat32Exp( a );

    aSign = extractFloat32Sign( a );

    shiftCount = aExp - 0xBE;

    if ( 0 <= shiftCount ) {

        if ( a != 0xDF000000 ) {

            float_raise( float_flag_invalid STATUS_VAR);

            if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {

                return LIT64( 0x7FFFFFFFFFFFFFFF );

            }

        }

        return (sbits64) LIT64( 0x8000000000000000 );

    }

    else if ( aExp <= 0x7E ) {

        if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact;

        return 0;

    }

    aSig64 = aSig | 0x00800000;

    aSig64 <<= 40;

    z = aSig64>>( - shiftCount );

    if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) {

        STATUS(float_exception_flags) |= float_flag_inexact;

    }

    if ( aSign ) z = - z;

    return z;

}


putsum(uint8_t *data, uint32_t n, uint32_t sloc, uint32_t css, uint32_t cse)

{

    if (cse && cse < n)

        n = cse + 1;

    if (sloc < n-1)

        cpu_to_be16wu((uint16_t *)(data + sloc),

                      do_cksum(data + css, data + n));

}


uint32_t HELPER(lcxbr)(CPUS390XState *env, uint32_t f1, uint32_t f2)

{

    CPU_QuadU x1, x2;

    x2.ll.upper = env->fregs[f2].ll;

    x2.ll.lower = env->fregs[f2 + 2].ll;

    x1.q = float128_chs(x2.q);

    env->fregs[f1].ll = x1.ll.upper;

    env->fregs[f1 + 2].ll = x1.ll.lower;

    return set_cc_nz_f128(x1.q);

}


static void pc_machine_set_nvdimm(Object *obj, bool value, Error **errp)

{

    PCMachineState *pcms = PC_MACHINE(obj);

    pcms->nvdimm = value;

}


static int dca_exss_parse_asset_header(DCAContext *s)

{

    int header_pos = get_bits_count(&s->gb);

    int header_size;

    int channels;

    int embedded_stereo = 0;

    int embedded_6ch    = 0;

    int drc_code_present;

    int extensions_mask;

    int i, j;

    if (get_bits_left(&s->gb) < 16)

        return -1;

    /* We will parse just enough to get to the extensions bitmask with which

     * we can set the profile value. */

    header_size = get_bits(&s->gb, 9) + 1;

    skip_bits(&s->gb, 3); // asset index

    if (s->static_fields) {

        if (get_bits1(&s->gb))

            skip_bits(&s->gb, 4); // asset type descriptor

        if (get_bits1(&s->gb))

            skip_bits_long(&s->gb, 24); // language descriptor

        if (get_bits1(&s->gb)) {

            /* How can one fit 1024 bytes of text here if the maximum value

             * for the asset header size field above was 512 bytes? */

            int text_length = get_bits(&s->gb, 10) + 1;

            if (get_bits_left(&s->gb) < text_length * 8)

                return -1;

            skip_bits_long(&s->gb, text_length * 8); // info text

        }

        skip_bits(&s->gb, 5); // bit resolution - 1

        skip_bits(&s->gb, 4); // max sample rate code

        channels = get_bits(&s->gb, 8) + 1;

        if (get_bits1(&s->gb)) { // 1-to-1 channels to speakers

            int spkr_remap_sets;

            int spkr_mask_size = 16;

            int num_spkrs[7];

            if (channels > 2)

                embedded_stereo = get_bits1(&s->gb);

            if (channels > 6)

                embedded_6ch = get_bits1(&s->gb);

            if (get_bits1(&s->gb)) {

                spkr_mask_size = (get_bits(&s->gb, 2) + 1) << 2;

                skip_bits(&s->gb, spkr_mask_size); // spkr activity mask

            }

            spkr_remap_sets = get_bits(&s->gb, 3);

            for (i = 0; i < spkr_remap_sets; i++) {

                /* std layout mask for each remap set */

                num_spkrs[i] = dca_exss_mask2count(get_bits(&s->gb, spkr_mask_size));

            }

            for (i = 0; i < spkr_remap_sets; i++) {

                int num_dec_ch_remaps = get_bits(&s->gb, 5) + 1;

                if (get_bits_left(&s->gb) < 0)

                    return -1;

                for (j = 0; j < num_spkrs[i]; j++) {

                    int remap_dec_ch_mask = get_bits_long(&s->gb, num_dec_ch_remaps);

                    int num_dec_ch = av_popcount(remap_dec_ch_mask);

                    skip_bits_long(&s->gb, num_dec_ch * 5); // remap codes

                }

            }

        } else {

            skip_bits(&s->gb, 3); // representation type

        }

    }

    drc_code_present = get_bits1(&s->gb);

    if (drc_code_present)

        get_bits(&s->gb, 8); // drc code

    if (get_bits1(&s->gb))

        skip_bits(&s->gb, 5); // dialog normalization code

    if (drc_code_present && embedded_stereo)

        get_bits(&s->gb, 8); // drc stereo code

    if (s->mix_metadata && get_bits1(&s->gb)) {

        skip_bits(&s->gb, 1); // external mix

        skip_bits(&s->gb, 6); // post mix gain code

        if (get_bits(&s->gb, 2) != 3) // mixer drc code

            skip_bits(&s->gb, 3); // drc limit

        else

            skip_bits(&s->gb, 8); // custom drc code

        if (get_bits1(&s->gb)) // channel specific scaling

            for (i = 0; i < s->num_mix_configs; i++)

                skip_bits_long(&s->gb, s->mix_config_num_ch[i] * 6); // scale codes

        else

            skip_bits_long(&s->gb, s->num_mix_configs * 6); // scale codes

        for (i = 0; i < s->num_mix_configs; i++) {

            if (get_bits_left(&s->gb) < 0)

                return -1;

            dca_exss_skip_mix_coeffs(&s->gb, channels, s->mix_config_num_ch[i]);

            if (embedded_6ch)

                dca_exss_skip_mix_coeffs(&s->gb, 6, s->mix_config_num_ch[i]);

            if (embedded_stereo)

                dca_exss_skip_mix_coeffs(&s->gb, 2, s->mix_config_num_ch[i]);

        }

    }

    switch (get_bits(&s->gb, 2)) {

    case 0:

        extensions_mask = get_bits(&s->gb, 12);

        break;

    case 1:

        extensions_mask = DCA_EXT_EXSS_XLL;

        break;

    case 2:

        extensions_mask = DCA_EXT_EXSS_LBR;

        break;

    case 3:

        extensions_mask = 0; /* aux coding */

        break;

    }

    /* not parsed further, we were only interested in the extensions mask */

    if (get_bits_left(&s->gb) < 0)

        return -1;

    if (get_bits_count(&s->gb) - header_pos > header_size * 8) {

        av_log(s->avctx, AV_LOG_WARNING, "Asset header size mismatch.\n");

        return -1;

    }

    skip_bits_long(&s->gb, header_pos + header_size * 8 - get_bits_count(&s->gb));

    if (extensions_mask & DCA_EXT_EXSS_XLL)

        s->profile = FF_PROFILE_DTS_HD_MA;

    else if (extensions_mask & (DCA_EXT_EXSS_XBR | DCA_EXT_EXSS_X96 |

                                DCA_EXT_EXSS_XXCH))

        s->profile = FF_PROFILE_DTS_HD_HRA;

    if (!(extensions_mask & DCA_EXT_CORE))

        av_log(s->avctx, AV_LOG_WARNING, "DTS core detection mismatch.\n");

    if ((extensions_mask & DCA_CORE_EXTS) != s->core_ext_mask)

        av_log(s->avctx, AV_LOG_WARNING,

               "DTS extensions detection mismatch (%d, %d)\n",

               extensions_mask & DCA_CORE_EXTS, s->core_ext_mask);

    return 0;

}


static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)

{

    UHCIPort *port;

    USBDevice *dev;

    int i, ret;

#ifdef DEBUG_PACKET

    {

        const char *pidstr;

        switch(p->pid) {

        case USB_TOKEN_SETUP: pidstr = "SETUP"; break;

        case USB_TOKEN_IN: pidstr = "IN"; break;

        case USB_TOKEN_OUT: pidstr = "OUT"; break;

        default: pidstr = "?"; break;

        }

        printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",

               s->frnum, pidstr, p->devaddr, p->devep, p->len);

        if (p->pid != USB_TOKEN_IN) {

            printf("     data_out=");

            for(i = 0; i < p->len; i++) {

                printf(" %02x", p->data[i]);

            }

            printf("\n");

        }

    }

#endif

    for(i = 0; i < NB_PORTS; i++) {

        port = &s->ports[i];

        dev = port->port.dev;

        if (dev && (port->ctrl & UHCI_PORT_EN)) {

            ret = dev->handle_packet(dev, p);

            if (ret != USB_RET_NODEV) {

#ifdef DEBUG_PACKET

                if (ret == USB_RET_ASYNC) {

                    printf("usb-uhci: Async packet\n");

                } else {

                    printf("     ret=%d ", ret);

                    if (p->pid == USB_TOKEN_IN && ret > 0) {

                        printf("data_in=");

                        for(i = 0; i < ret; i++) {

                            printf(" %02x", p->data[i]);

                        }

                    }

                    printf("\n");

                }

#endif

                return ret;

            }

        }

    }

    return USB_RET_NODEV;

}


static inline PageDesc *page_find_alloc(target_ulong index)

{

    PageDesc **lp, *p;

    lp = page_l1_map(index);

    if (!lp)

        return NULL;

    p = *lp;

    if (!p) {

        /* allocate if not found */

#if defined(CONFIG_USER_ONLY)

        unsigned long addr;

        size_t len = sizeof(PageDesc) * L2_SIZE;

        /* Don't use qemu_malloc because it may recurse.  */

        p = mmap(0, len, PROT_READ | PROT_WRITE,

                 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        *lp = p;

        addr = h2g(p);

        if (addr == (target_ulong)addr) {

            page_set_flags(addr & TARGET_PAGE_MASK,

                           TARGET_PAGE_ALIGN(addr + len),

                           PAGE_RESERVED);

        }

#else

        p = qemu_mallocz(sizeof(PageDesc) * L2_SIZE);

        *lp = p;

#endif

    }

    return p + (index & (L2_SIZE - 1));

}


static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)

{

    DeviceState *dev = DEVICE(cpu);

    APICCommonState *apic;

    const char *apic_type = "apic";

    if (kvm_irqchip_in_kernel()) {

        apic_type = "kvm-apic";

    } else if (xen_enabled()) {

        apic_type = "xen-apic";

    }

    cpu->apic_state = qdev_try_create(qdev_get_parent_bus(dev), apic_type);

    if (cpu->apic_state == NULL) {

        error_setg(errp, "APIC device '%s' could not be created", apic_type);

        return;

    }

    object_property_add_child(OBJECT(cpu), "apic",

                              OBJECT(cpu->apic_state), NULL);

    qdev_prop_set_uint8(cpu->apic_state, "id", cpu->apic_id);

    /* TODO: convert to link<> */

    apic = APIC_COMMON(cpu->apic_state);

    apic->cpu = cpu;

    apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;

}


int select_watchdog_action(const char *p)

{

    int action;

    char *qapi_value;

    qapi_value = g_ascii_strdown(p, -1);

    action = qapi_enum_parse(&WatchdogAction_lookup, qapi_value, -1, NULL);

    g_free(qapi_value);

    if (action < 0)

        return -1;

    watchdog_action = action;

    return 0;

}


static void pty_chr_read(void *opaque)

{

    CharDriverState *chr = opaque;

    PtyCharDriver *s = chr->opaque;

    int size, len;

    uint8_t buf[1024];

    len = sizeof(buf);

    if (len > s->read_bytes)

        len = s->read_bytes;

    if (len == 0)

        return;

    size = read(s->fd, buf, len);

    if ((size == -1 && errno == EIO) ||

        (size == 0)) {

        pty_chr_state(chr, 0);

        return;

    }

    if (size > 0) {

        pty_chr_state(chr, 1);

        qemu_chr_read(chr, buf, size);

    }

}


static void test_visitor_out_struct(TestOutputVisitorData *data,

                                    const void *unused)

{

    TestStruct test_struct = { .integer = 42,

                               .boolean = false,

                               .string = (char *) "foo"};

    TestStruct *p = &test_struct;

    QObject *obj;

    QDict *qdict;

    visit_type_TestStruct(data->ov, NULL, &p, &error_abort);

    obj = visitor_get(data);

    g_assert(qobject_type(obj) == QTYPE_QDICT);

    qdict = qobject_to_qdict(obj);

    g_assert_cmpint(qdict_size(qdict), ==, 3);

    g_assert_cmpint(qdict_get_int(qdict, "integer"), ==, 42);

    g_assert_cmpint(qdict_get_bool(qdict, "boolean"), ==, false);

    g_assert_cmpstr(qdict_get_str(qdict, "string"), ==, "foo");

}


static inline int check_ap(CPUARMState *env, ARMMMUIdx mmu_idx,

                           int ap, int domain_prot,

                           int access_type)

{

    int prot_ro;

    bool is_user = regime_is_user(env, mmu_idx);

    if (domain_prot == 3) {

        return PAGE_READ | PAGE_WRITE;

    }

    if (access_type == 1) {

        prot_ro = 0;

    } else {

        prot_ro = PAGE_READ;

    }

    switch (ap) {

    case 0:

        if (arm_feature(env, ARM_FEATURE_V7)) {

            return 0;

        }

        if (access_type == 1) {

            return 0;

        }

        switch (regime_sctlr(env, mmu_idx) & (SCTLR_S | SCTLR_R)) {

        case SCTLR_S:

            return is_user ? 0 : PAGE_READ;

        case SCTLR_R:

            return PAGE_READ;

        default:

            return 0;

        }

    case 1:

        return is_user ? 0 : PAGE_READ | PAGE_WRITE;

    case 2:

        if (is_user) {

            return prot_ro;

        } else {

            return PAGE_READ | PAGE_WRITE;

        }

    case 3:

        return PAGE_READ | PAGE_WRITE;

    case 4: /* Reserved.  */

        return 0;

    case 5:

        return is_user ? 0 : prot_ro;

    case 6:

        return prot_ro;

    case 7:

        if (!arm_feature(env, ARM_FEATURE_V6K)) {

            return 0;

        }

        return prot_ro;

    default:

        abort();

    }

}


static int posix_aio_flush(void *opaque)

{

    PosixAioState *s = opaque;

    return !!s->first_aio;

}


static MemoryRegionSection *address_space_lookup_region(AddressSpaceDispatch *d,

                                                        hwaddr addr,

                                                        bool resolve_subpage)

{

    MemoryRegionSection *section;

    subpage_t *subpage;

    section = phys_page_find(d->phys_map, addr, d->map.nodes, d->map.sections);

    if (resolve_subpage && section->mr->subpage) {

        subpage = container_of(section->mr, subpage_t, iomem);

        section = &d->map.sections[subpage->sub_section[SUBPAGE_IDX(addr)]];

    }

    return section;

}


static void finish_read_pci_config(sPAPREnvironment *spapr, uint64_t buid,

                                   uint32_t addr, uint32_t size,

                                   target_ulong rets)

{

    PCIDevice *pci_dev;

    uint32_t val;

    if ((size != 1) && (size != 2) && (size != 4)) {

        /* access must be 1, 2 or 4 bytes */

        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

        return;

    }

    pci_dev = find_dev(spapr, buid, addr);

    addr = rtas_pci_cfgaddr(addr);

    if (!pci_dev || (addr % size) || (addr >= pci_config_size(pci_dev))) {

        /* Access must be to a valid device, within bounds and

         * naturally aligned */

        rtas_st(rets, 0, RTAS_OUT_HW_ERROR);

        return;

    }

    val = pci_host_config_read_common(pci_dev, addr,

                                      pci_config_size(pci_dev), size);

    rtas_st(rets, 0, RTAS_OUT_SUCCESS);

    rtas_st(rets, 1, val);

}


static void RENAME(interleaveBytes)(const uint8_t *src1, const uint8_t *src2, uint8_t *dest,

                             long width, long height, long src1Stride,

                             long src2Stride, long dstStride)

{

    long h;

    for (h=0; h < height; h++) {

        long w;

#if COMPILE_TEMPLATE_MMX

#if COMPILE_TEMPLATE_SSE2

        __asm__(

            "xor              %%"REG_a", %%"REG_a"  \n\t"

            "1:                                     \n\t"

            PREFETCH" 64(%1, %%"REG_a")             \n\t"

            PREFETCH" 64(%2, %%"REG_a")             \n\t"

            "movdqa     (%1, %%"REG_a"), %%xmm0     \n\t"

            "movdqa     (%1, %%"REG_a"), %%xmm1     \n\t"

            "movdqa     (%2, %%"REG_a"), %%xmm2     \n\t"

            "punpcklbw           %%xmm2, %%xmm0     \n\t"

            "punpckhbw           %%xmm2, %%xmm1     \n\t"

            "movntdq             %%xmm0,   (%0, %%"REG_a", 2)   \n\t"

            "movntdq             %%xmm1, 16(%0, %%"REG_a", 2)   \n\t"

            "add                    $16, %%"REG_a"  \n\t"

            "cmp                     %3, %%"REG_a"  \n\t"

            " jb                     1b             \n\t"

            ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15)

            : "memory", "%"REG_a""

        );

#else

        __asm__(

            "xor %%"REG_a", %%"REG_a"               \n\t"

            "1:                                     \n\t"

            PREFETCH" 64(%1, %%"REG_a")             \n\t"

            PREFETCH" 64(%2, %%"REG_a")             \n\t"

            "movq       (%1, %%"REG_a"), %%mm0      \n\t"

            "movq      8(%1, %%"REG_a"), %%mm2      \n\t"

            "movq                 %%mm0, %%mm1      \n\t"

            "movq                 %%mm2, %%mm3      \n\t"

            "movq       (%2, %%"REG_a"), %%mm4      \n\t"

            "movq      8(%2, %%"REG_a"), %%mm5      \n\t"

            "punpcklbw            %%mm4, %%mm0      \n\t"

            "punpckhbw            %%mm4, %%mm1      \n\t"

            "punpcklbw            %%mm5, %%mm2      \n\t"

            "punpckhbw            %%mm5, %%mm3      \n\t"

            MOVNTQ"               %%mm0,   (%0, %%"REG_a", 2)   \n\t"

            MOVNTQ"               %%mm1,  8(%0, %%"REG_a", 2)   \n\t"

            MOVNTQ"               %%mm2, 16(%0, %%"REG_a", 2)   \n\t"

            MOVNTQ"               %%mm3, 24(%0, %%"REG_a", 2)   \n\t"

            "add                    $16, %%"REG_a"  \n\t"

            "cmp                     %3, %%"REG_a"  \n\t"

            " jb                     1b             \n\t"

            ::"r"(dest), "r"(src1), "r"(src2), "r" ((x86_reg)width-15)

            : "memory", "%"REG_a

        );

#endif

        for (w= (width&(~15)); w < width; w++) {

            dest[2*w+0] = src1[w];

            dest[2*w+1] = src2[w];

        }

#else

        for (w=0; w < width; w++) {

            dest[2*w+0] = src1[w];

            dest[2*w+1] = src2[w];

        }

#endif

        dest += dstStride;

        src1 += src1Stride;

        src2 += src2Stride;

    }

#if COMPILE_TEMPLATE_MMX

    __asm__(

            EMMS"       \n\t"

            SFENCE"     \n\t"

            ::: "memory"

            );

#endif

}


static int spapr_nvram_init(VIOsPAPRDevice *dev)

{

    sPAPRNVRAM *nvram = VIO_SPAPR_NVRAM(dev);

    if (nvram->drive) {

        nvram->size = bdrv_getlength(nvram->drive);

    } else {

        nvram->size = DEFAULT_NVRAM_SIZE;

        nvram->buf = g_malloc0(nvram->size);

    }

    if ((nvram->size < MIN_NVRAM_SIZE) || (nvram->size > MAX_NVRAM_SIZE)) {

        fprintf(stderr, "spapr-nvram must be between %d and %d bytes in size\n",

                MIN_NVRAM_SIZE, MAX_NVRAM_SIZE);

        return -1;

    }

    spapr_rtas_register(RTAS_NVRAM_FETCH, "nvram-fetch", rtas_nvram_fetch);

    spapr_rtas_register(RTAS_NVRAM_STORE, "nvram-store", rtas_nvram_store);

    return 0;

}


static void test_io_channel_setup_async(SocketAddress *listen_addr,

                                        SocketAddress *connect_addr,

                                        QIOChannel **src,

                                        QIOChannel **dst)

{

    QIOChannelSocket *lioc;

    struct TestIOChannelData data;

    data.loop = g_main_loop_new(g_main_context_default(),

                                TRUE);

    lioc = qio_channel_socket_new();

    qio_channel_socket_listen_async(

        lioc, listen_addr,

        test_io_channel_complete, &data, NULL);

    g_main_loop_run(data.loop);

    g_main_context_iteration(g_main_context_default(), FALSE);

    g_assert(!data.err);

    if (listen_addr->type == SOCKET_ADDRESS_KIND_INET) {

        SocketAddress *laddr = qio_channel_socket_get_local_address(

            lioc, &error_abort);

        g_free(connect_addr->u.inet.data->port);

        connect_addr->u.inet.data->port = g_strdup(laddr->u.inet.data->port);

        qapi_free_SocketAddress(laddr);

    }

    *src = QIO_CHANNEL(qio_channel_socket_new());

    qio_channel_socket_connect_async(

        QIO_CHANNEL_SOCKET(*src), connect_addr,

        test_io_channel_complete, &data, NULL);

    g_main_loop_run(data.loop);

    g_main_context_iteration(g_main_context_default(), FALSE);

    g_assert(!data.err);

    qio_channel_wait(QIO_CHANNEL(lioc), G_IO_IN);

    *dst = QIO_CHANNEL(qio_channel_socket_accept(lioc, &error_abort));

    g_assert(*dst);

    qio_channel_set_delay(*src, false);

    test_io_channel_set_socket_bufs(*src, *dst);

    object_unref(OBJECT(lioc));

    g_main_loop_unref(data.loop);

}


iscsi_process_read(void *arg)

{

    IscsiLun *iscsilun = arg;

    struct iscsi_context *iscsi = iscsilun->iscsi;

    aio_context_acquire(iscsilun->aio_context);

    iscsi_service(iscsi, POLLIN);

    iscsi_set_events(iscsilun);

    aio_context_release(iscsilun->aio_context);

}


static int local_open2(FsContext *ctx, const char *path, int flags, mode_t mode)

{

    return open(rpath(ctx, path), flags, mode);

}


static int cpu_common_load(QEMUFile *f, void *opaque, int version_id)

{

    CPUState *env = opaque;

    if (version_id != CPU_COMMON_SAVE_VERSION)

        return -EINVAL;

    qemu_get_be32s(f, &env->halted);

    qemu_get_be32s(f, &env->interrupt_request);

    env->interrupt_request &= ~CPU_INTERRUPT_EXIT;

    tlb_flush(env, 1);

    return 0;

}


static void xhci_port_reset(XHCIPort *port)

{

    trace_usb_xhci_port_reset(port->portnr);

    if (!xhci_port_have_device(port)) {

        return;

    }

    usb_device_reset(port->uport->dev);

    switch (port->uport->dev->speed) {

    case USB_SPEED_LOW:

    case USB_SPEED_FULL:

    case USB_SPEED_HIGH:

        set_field(&port->portsc, PLS_U0, PORTSC_PLS);

        trace_usb_xhci_port_link(port->portnr, PLS_U0);

        port->portsc |= PORTSC_PED;

        break;

    }

    port->portsc &= ~PORTSC_PR;

    xhci_port_notify(port, PORTSC_PRC);

}


static int block_crypto_create_generic(QCryptoBlockFormat format,

                                       const char *filename,

                                       QemuOpts *opts,

                                       Error **errp)

{

    int ret = -EINVAL;

    QCryptoBlockCreateOptions *create_opts = NULL;

    QCryptoBlock *crypto = NULL;

    struct BlockCryptoCreateData data = {

        .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),

                         BDRV_SECTOR_SIZE),

        .opts = opts,

        .filename = filename,

    };

    create_opts = block_crypto_create_opts_init(format, opts, errp);

    if (!create_opts) {

        return -1;

    }

    crypto = qcrypto_block_create(create_opts,

                                  block_crypto_init_func,

                                  block_crypto_write_func,

                                  &data,

                                  errp);

    if (!crypto) {

        ret = -EIO;

        goto cleanup;

    }

    ret = 0;

 cleanup:

    qcrypto_block_free(crypto);

    blk_unref(data.blk);

    qapi_free_QCryptoBlockCreateOptions(create_opts);

    return ret;

}


static void vertical_filter(unsigned char *first_pixel, int stride,

    int *bounding_values)

{

    int i;

    int filter_value;

    for (i = 0; i < 8; i++, first_pixel++) {

        filter_value =

            (first_pixel[-(2 * stride)] * 1) -

            (first_pixel[-(1 * stride)] * 3) +

            (first_pixel[ (0         )] * 3) -

            (first_pixel[ (1 * stride)] * 1);

        filter_value = bounding_values[(filter_value + 4) >> 3];

        first_pixel[-(1 * stride)] = SATURATE_U8(first_pixel[-(1 * stride)] + filter_value);

        first_pixel[0] = SATURATE_U8(first_pixel[0] - filter_value);

    }

}


POWERPC_FAMILY(POWER8)(ObjectClass *oc, void *data)

{

    DeviceClass *dc = DEVICE_CLASS(oc);

    PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);

    dc->fw_name = "PowerPC,POWER8";

    dc->desc = "POWER8";

    dc->props = powerpc_servercpu_properties;

    pcc->pvr_match = ppc_pvr_match_power8;

    pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;

    pcc->init_proc = init_proc_POWER8;

    pcc->check_pow = check_pow_nocheck;

    pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |

                       PPC_FLOAT | PPC_FLOAT_FSEL | PPC_FLOAT_FRES |

                       PPC_FLOAT_FSQRT | PPC_FLOAT_FRSQRTE |

                       PPC_FLOAT_FRSQRTES |

                       PPC_FLOAT_STFIWX |

                       PPC_FLOAT_EXT |

                       PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |

                       PPC_MEM_SYNC | PPC_MEM_EIEIO |

                       PPC_MEM_TLBIE | PPC_MEM_TLBSYNC |

                       PPC_64B | PPC_64H | PPC_64BX | PPC_ALTIVEC |

                       PPC_SEGMENT_64B | PPC_SLBI |

                       PPC_POPCNTB | PPC_POPCNTWD;

    pcc->insns_flags2 = PPC2_VSX | PPC2_VSX207 | PPC2_DFP | PPC2_DBRX |

                        PPC2_PERM_ISA206 | PPC2_DIVE_ISA206 |

                        PPC2_ATOMIC_ISA206 | PPC2_FP_CVT_ISA206 |

                        PPC2_FP_TST_ISA206 | PPC2_BCTAR_ISA207 |

                        PPC2_LSQ_ISA207 | PPC2_ALTIVEC_207 |

                        PPC2_ISA205 | PPC2_ISA207S | PPC2_FP_CVT_S64 |

                        PPC2_TM;

    pcc->msr_mask = (1ull << MSR_SF) |

                    (1ull << MSR_SHV) |

                    (1ull << MSR_TM) |

                    (1ull << MSR_VR) |

                    (1ull << MSR_VSX) |

                    (1ull << MSR_EE) |

                    (1ull << MSR_PR) |

                    (1ull << MSR_FP) |

                    (1ull << MSR_ME) |

                    (1ull << MSR_FE0) |

                    (1ull << MSR_SE) |

                    (1ull << MSR_DE) |

                    (1ull << MSR_FE1) |

                    (1ull << MSR_IR) |

                    (1ull << MSR_DR) |

                    (1ull << MSR_PMM) |

                    (1ull << MSR_RI) |

                    (1ull << MSR_LE);

    pcc->mmu_model = POWERPC_MMU_2_07;

#if defined(CONFIG_SOFTMMU)

    pcc->handle_mmu_fault = ppc_hash64_handle_mmu_fault;

    pcc->sps = &POWER7_POWER8_sps;

#endif

    pcc->excp_model = POWERPC_EXCP_POWER8;

    pcc->bus_model = PPC_FLAGS_INPUT_POWER7;

    pcc->bfd_mach = bfd_mach_ppc64;

    pcc->flags = POWERPC_FLAG_VRE | POWERPC_FLAG_SE |

                 POWERPC_FLAG_BE | POWERPC_FLAG_PMM |

                 POWERPC_FLAG_BUS_CLK | POWERPC_FLAG_CFAR |

                 POWERPC_FLAG_VSX | POWERPC_FLAG_TM;

    pcc->l1_dcache_size = 0x8000;

    pcc->l1_icache_size = 0x8000;

    pcc->interrupts_big_endian = ppc_cpu_interrupts_big_endian_lpcr;

}


void qemu_aio_set_fd_handler(int fd,

                             IOHandler *io_read,

                             IOHandler *io_write,

                             AioFlushHandler *io_flush,

                             void *opaque)

{

    aio_set_fd_handler(qemu_aio_context, fd, io_read, io_write, io_flush,

                       opaque);

    qemu_set_fd_handler2(fd, NULL, io_read, io_write, opaque);

}


static void apb_pci_config_write(void *opaque, target_phys_addr_t addr,

                                 uint64_t val, unsigned size)

{

    APBState *s = opaque;

    val = qemu_bswap_len(val, size);

    APB_DPRINTF("%s: addr " TARGET_FMT_lx " val %" PRIx64 "\n", __func__, addr, val);

    pci_data_write(s->bus, addr, val, size);

}


static inline bool extended_addresses_enabled(CPUARMState *env)

{

    return arm_el_is_aa64(env, 1)

        || ((arm_feature(env, ARM_FEATURE_LPAE)

             && (env->cp15.c2_control & (1U << 31))));

}


void qmp_block_job_pause(const char *device, Error **errp)

{

    BlockJob *job = find_block_job(device);

    if (!job) {

        error_set(errp, QERR_BLOCK_JOB_NOT_ACTIVE, device);

        return;

    }

    trace_qmp_block_job_pause(job);

    block_job_pause(job);

}


void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds)

{

    struct socket *so, *so_next;

    int ret;

    global_readfds = readfds;

    global_writefds = writefds;

    global_xfds = xfds;

	/* Update time */

	updtime();

	/*

	 * See if anything has timed out

	 */

	if (link_up) {

		if (time_fasttimo && ((curtime - time_fasttimo) >= 2)) {

			tcp_fasttimo();

			time_fasttimo = 0;

		}

		if (do_slowtimo && ((curtime - last_slowtimo) >= 499)) {

			ip_slowtimo();

			tcp_slowtimo();

			last_slowtimo = curtime;

		}

	}

	/*

	 * Check sockets

	 */

	if (link_up) {

		/*

		 * Check TCP sockets

		 */

		for (so = tcb.so_next; so != &tcb; so = so_next) {

			so_next = so->so_next;

			/*

			 * FD_ISSET is meaningless on these sockets

			 * (and they can crash the program)

			 */

			if (so->so_state & SS_NOFDREF || so->s == -1)

			   continue;

			/*

			 * Check for URG data

			 * This will soread as well, so no need to

			 * test for readfds below if this succeeds

			 */

			if (FD_ISSET(so->s, xfds))

			   sorecvoob(so);

			/*

			 * Check sockets for reading

			 */

			else if (FD_ISSET(so->s, readfds)) {

				/*

				 * Check for incoming connections

				 */

				if (so->so_state & SS_FACCEPTCONN) {

					tcp_connect(so);

					continue;

				} /* else */

				ret = soread(so);

				/* Output it if we read something */

				if (ret > 0)

				   tcp_output(sototcpcb(so));

			}

			/*

			 * Check sockets for writing

			 */

			if (FD_ISSET(so->s, writefds)) {

			  /*

			   * Check for non-blocking, still-connecting sockets

			   */

			  if (so->so_state & SS_ISFCONNECTING) {

			    /* Connected */

			    so->so_state &= ~SS_ISFCONNECTING;

			    ret = send(so->s, (const void *) &ret, 0, 0);

			    if (ret < 0) {

			      /* XXXXX Must fix, zero bytes is a NOP */

			      if (errno == EAGAIN || errno == EWOULDBLOCK ||

				  errno == EINPROGRESS || errno == ENOTCONN)

				continue;

			      /* else failed */

			      so->so_state &= SS_PERSISTENT_MASK;

			      so->so_state |= SS_NOFDREF;

			    }

			    /* else so->so_state &= ~SS_ISFCONNECTING; */

			    /*

			     * Continue tcp_input

			     */

			    tcp_input((struct mbuf *)NULL, sizeof(struct ip), so);

			    /* continue; */

			  } else

			    ret = sowrite(so);

			  /*

			   * XXXXX If we wrote something (a lot), there

			   * could be a need for a window update.

			   * In the worst case, the remote will send

			   * a window probe to get things going again

			   */

			}

			/*

			 * Probe a still-connecting, non-blocking socket

			 * to check if it's still alive

	 	 	 */

#ifdef PROBE_CONN

			if (so->so_state & SS_ISFCONNECTING) {

			  ret = recv(so->s, (char *)&ret, 0,0);

			  if (ret < 0) {

			    /* XXX */

			    if (errno == EAGAIN || errno == EWOULDBLOCK ||

				errno == EINPROGRESS || errno == ENOTCONN)

			      continue; /* Still connecting, continue */

			    /* else failed */

			    so->so_state &= SS_PERSISTENT_MASK;

			    so->so_state |= SS_NOFDREF;

			    /* tcp_input will take care of it */

			  } else {

			    ret = send(so->s, &ret, 0,0);

			    if (ret < 0) {

			      /* XXX */

			      if (errno == EAGAIN || errno == EWOULDBLOCK ||

				  errno == EINPROGRESS || errno == ENOTCONN)

				continue;

			      /* else failed */

			      so->so_state &= SS_PERSISTENT_MASK;

			      so->so_state |= SS_NOFDREF;

			    } else

			      so->so_state &= ~SS_ISFCONNECTING;

			  }

			  tcp_input((struct mbuf *)NULL, sizeof(struct ip),so);

			} /* SS_ISFCONNECTING */

#endif

		}

		/*

		 * Now UDP sockets.

		 * Incoming packets are sent straight away, they're not buffered.

		 * Incoming UDP data isn't buffered either.

		 */

		for (so = udb.so_next; so != &udb; so = so_next) {

			so_next = so->so_next;

			if (so->s != -1 && FD_ISSET(so->s, readfds)) {

                            sorecvfrom(so);

                        }

		}

	}

	/*

	 * See if we can start outputting

	 */

	if (if_queued && link_up)

	   if_start();

	/* clear global file descriptor sets.

	 * these reside on the stack in vl.c

	 * so they're unusable if we're not in

	 * slirp_select_fill or slirp_select_poll.

	 */

	 global_readfds = NULL;

	 global_writefds = NULL;

	 global_xfds = NULL;

}


static void raise_mmu_exception(CPUMIPSState *env, target_ulong address,

                                int rw, int tlb_error)

{

    CPUState *cs = CPU(mips_env_get_cpu(env));

    int exception = 0, error_code = 0;

    switch (tlb_error) {

    default:

    case TLBRET_BADADDR:

        /* Reference to kernel address from user mode or supervisor mode */

        /* Reference to supervisor address from user mode */

        if (rw == MMU_DATA_STORE) {

            exception = EXCP_AdES;

        } else {

            exception = EXCP_AdEL;

        }

        break;

    case TLBRET_NOMATCH:

        /* No TLB match for a mapped address */

        if (rw == MMU_DATA_STORE) {

            exception = EXCP_TLBS;

        } else {

            exception = EXCP_TLBL;

        }

        error_code = 1;

        break;

    case TLBRET_INVALID:

        /* TLB match with no valid bit */

        if (rw == MMU_DATA_STORE) {

            exception = EXCP_TLBS;

        } else {

            exception = EXCP_TLBL;

        }

        break;

    case TLBRET_DIRTY:

        /* TLB match but 'D' bit is cleared */

        exception = EXCP_LTLBL;

        break;

    case TLBRET_XI:

        /* Execute-Inhibit Exception */

        if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {

            exception = EXCP_TLBXI;

        } else {

            exception = EXCP_TLBL;

        }

        break;

    case TLBRET_RI:

        /* Read-Inhibit Exception */

        if (env->CP0_PageGrain & (1 << CP0PG_IEC)) {

            exception = EXCP_TLBRI;

        } else {

            exception = EXCP_TLBL;

        }

        break;

    }

    /* Raise exception */

    env->CP0_BadVAddr = address;

    env->CP0_Context = (env->CP0_Context & ~0x007fffff) |

                       ((address >> 9) & 0x007ffff0);

    env->CP0_EntryHi =

        (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));

#if defined(TARGET_MIPS64)

    env->CP0_EntryHi &= env->SEGMask;

    env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |

                        ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |

                        ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);

#endif

    cs->exception_index = exception;

    env->error_code = error_code;

}


void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src,

                                ptrdiff_t stride)

{

    avc_luma_hz_4w_msa(src - 2, stride, dst, stride, 4);

}


static int roq_encode_video(RoqContext *enc)

{

    RoqTempdata *tempData = enc->tmpData;

    int i, ret;

    memset(tempData, 0, sizeof(*tempData));

    ret = create_cel_evals(enc, tempData);

    if (ret < 0)

        return ret;

    ret = generate_new_codebooks(enc, tempData);

    if (ret < 0)

        return ret;

    if (enc->framesSinceKeyframe >= 1) {

        motion_search(enc, 8);

        motion_search(enc, 4);

    }

 retry_encode:

    for (i=0; i<enc->width*enc->height/64; i++)

        gather_data_for_cel(tempData->cel_evals + i, enc, tempData);

    /* Quake 3 can't handle chunks bigger than 65535 bytes */

    if (tempData->mainChunkSize/8 > 65535) {

        av_log(enc->avctx, AV_LOG_ERROR,

               "Warning, generated a frame too big (%d > 65535), "

               "try using a smaller qscale value.\n",

               tempData->mainChunkSize/8);

        enc->lambda *= 1.5;

        tempData->mainChunkSize = 0;

        memset(tempData->used_option, 0, sizeof(tempData->used_option));

        memset(tempData->codebooks.usedCB4, 0,

               sizeof(tempData->codebooks.usedCB4));

        memset(tempData->codebooks.usedCB2, 0,

               sizeof(tempData->codebooks.usedCB2));

        goto retry_encode;

    }

    remap_codebooks(enc, tempData);

    write_codebooks(enc, tempData);

    reconstruct_and_encode_image(enc, tempData, enc->width, enc->height,

                                 enc->width*enc->height/64);

    enc->avctx->coded_frame = enc->current_frame;

    /* Rotate frame history */

    FFSWAP(AVFrame *, enc->current_frame, enc->last_frame);

    FFSWAP(motion_vect *, enc->last_motion4, enc->this_motion4);

    FFSWAP(motion_vect *, enc->last_motion8, enc->this_motion8);

    av_free(tempData->cel_evals);

    av_free(tempData->closest_cb2);

    enc->framesSinceKeyframe++;

    return 0;

}


static int raw_read_packet(AVFormatContext *s, AVPacket *pkt)

{

    TAKDemuxContext *tc = s->priv_data;

    int ret;

    if (tc->mlast_frame) {

        AVIOContext *pb = s->pb;

        int64_t size, left;

        left = tc->data_end - avio_tell(s->pb);

        size = FFMIN(left, 1024);

        if (size <= 0)

            return AVERROR_EOF;

        ret = av_get_packet(pb, pkt, size);

        if (ret < 0)

            return ret;

        pkt->stream_index = 0;

    } else {

        ret = ff_raw_read_partial_packet(s, pkt);

    }

    return ret;

}


uint64_t helper_mullv (uint64_t op1, uint64_t op2)

{

    int64_t res = (int64_t)op1 * (int64_t)op2;

    if (unlikely((int32_t)res != res)) {

        arith_excp(env, GETPC(), EXC_M_IOV, 0);

    }

    return (int64_t)((int32_t)res);

}


uint32_t hpet_in_legacy_mode(void)

{

    if (hpet_statep)

        return hpet_statep->config & HPET_CFG_LEGACY;

    else

        return 0;

}


make_setup_request (AVFormatContext *s, const char *host, int port,

                    int lower_transport, const char *real_challenge)

{

    RTSPState *rt = s->priv_data;

    int j, i, err;

    RTSPStream *rtsp_st;

    RTSPHeader reply1, *reply = &reply1;

    char cmd[2048];

    const char *trans_pref;

    if (rt->server_type == RTSP_SERVER_REAL)

        trans_pref = "x-pn-tng";

    else

        trans_pref = "RTP/AVP";

    /* for each stream, make the setup request */

    /* XXX: we assume the same server is used for the control of each

       RTSP stream */

    for(j = RTSP_RTP_PORT_MIN, i = 0; i < rt->nb_rtsp_streams; ++i) {

        char transport[2048];

        rtsp_st = rt->rtsp_streams[i];

        /* RTP/UDP */

        if (lower_transport == RTSP_LOWER_TRANSPORT_UDP) {

            char buf[256];

            /* first try in specified port range */

            if (RTSP_RTP_PORT_MIN != 0) {

                while(j <= RTSP_RTP_PORT_MAX) {

                    snprintf(buf, sizeof(buf), "rtp://%s?localport=%d", host, j);

                    j += 2; /* we will use two port by rtp stream (rtp and rtcp) */

                    if (url_open(&rtsp_st->rtp_handle, buf, URL_RDWR) == 0) {

                        goto rtp_opened;

                    }

                }

            }

/*            then try on any port

**            if (url_open(&rtsp_st->rtp_handle, "rtp://", URL_RDONLY) < 0) {

**                err = AVERROR_INVALIDDATA;

**                goto fail;

**            }

*/

        rtp_opened:

            port = rtp_get_local_port(rtsp_st->rtp_handle);

            snprintf(transport, sizeof(transport) - 1,

                     "%s/UDP;unicast;client_port=%d",

                     trans_pref, port);

            if (rt->server_type == RTSP_SERVER_RTP)

                av_strlcatf(transport, sizeof(transport), "-%d", port + 1);

        }

        /* RTP/TCP */

        else if (lower_transport == RTSP_LOWER_TRANSPORT_TCP) {

            snprintf(transport, sizeof(transport) - 1,

                     "%s/TCP", trans_pref);

        }

        else if (lower_transport == RTSP_LOWER_TRANSPORT_UDP_MULTICAST) {

            snprintf(transport, sizeof(transport) - 1,

                     "%s/UDP;multicast", trans_pref);

        }

        if (rt->server_type == RTSP_SERVER_REAL)

            av_strlcat(transport, ";mode=play", sizeof(transport));

        snprintf(cmd, sizeof(cmd),

                 "SETUP %s RTSP/1.0\r\n"

                 "Transport: %s\r\n",

                 rtsp_st->control_url, transport);

        if (i == 0 && rt->server_type == RTSP_SERVER_REAL) {

            char real_res[41], real_csum[9];

            ff_rdt_calc_response_and_checksum(real_res, real_csum,

                                              real_challenge);

            av_strlcatf(cmd, sizeof(cmd),

                        "If-Match: %s\r\n"

                        "RealChallenge2: %s, sd=%s\r\n",

                        rt->session_id, real_res, real_csum);

        }

        rtsp_send_cmd(s, cmd, reply, NULL);

        if (reply->status_code == 461 /* Unsupported protocol */ && i == 0) {

            err = 1;

            goto fail;

        } else if (reply->status_code != RTSP_STATUS_OK ||

                   reply->nb_transports != 1) {

            err = AVERROR_INVALIDDATA;

            goto fail;

        }

        /* XXX: same protocol for all streams is required */

        if (i > 0) {

            if (reply->transports[0].lower_transport != rt->lower_transport) {

                err = AVERROR_INVALIDDATA;

                goto fail;

            }

        } else {

            rt->lower_transport = reply->transports[0].lower_transport;

        }

        /* close RTP connection if not choosen */

        if (reply->transports[0].lower_transport != RTSP_LOWER_TRANSPORT_UDP &&

            (lower_transport == RTSP_LOWER_TRANSPORT_UDP)) {

            url_close(rtsp_st->rtp_handle);

            rtsp_st->rtp_handle = NULL;

        }

        switch(reply->transports[0].lower_transport) {

        case RTSP_LOWER_TRANSPORT_TCP:

            rtsp_st->interleaved_min = reply->transports[0].interleaved_min;

            rtsp_st->interleaved_max = reply->transports[0].interleaved_max;

            break;

        case RTSP_LOWER_TRANSPORT_UDP:

            {

                char url[1024];

                /* XXX: also use address if specified */

                snprintf(url, sizeof(url), "rtp://%s:%d",

                         host, reply->transports[0].server_port_min);

                if (rtp_set_remote_url(rtsp_st->rtp_handle, url) < 0) {

                    err = AVERROR_INVALIDDATA;

                    goto fail;

                }

            }

            break;

        case RTSP_LOWER_TRANSPORT_UDP_MULTICAST:

            {

                char url[1024];

                struct in_addr in;

                in.s_addr = htonl(reply->transports[0].destination);

                snprintf(url, sizeof(url), "rtp://%s:%d?ttl=%d",

                         inet_ntoa(in),

                         reply->transports[0].port_min,

                         reply->transports[0].ttl);

                if (url_open(&rtsp_st->rtp_handle, url, URL_RDWR) < 0) {

                    err = AVERROR_INVALIDDATA;

                    goto fail;

                }

            }

            break;

        }

        if ((err = rtsp_open_transport_ctx(s, rtsp_st)))

            goto fail;

    }

    if (rt->server_type == RTSP_SERVER_REAL)

        rt->need_subscription = 1;

    return 0;

fail:

    for (i=0; i<rt->nb_rtsp_streams; i++) {

        if (rt->rtsp_streams[i]->rtp_handle) {

            url_close(rt->rtsp_streams[i]->rtp_handle);

            rt->rtsp_streams[i]->rtp_handle = NULL;

        }

    }

    return err;

}


static int ipvideo_decode_frame(AVCodecContext *avctx,
                                void *data, int *got_frame,
                                AVPacket *avpkt)
{
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
    IpvideoContext *s = avctx->priv_data;
    AVFrame *frame = data;
    int ret;
    int send_buffer;
    int frame_format;
    int video_data_size;
    if (av_packet_get_side_data(avpkt, AV_PKT_DATA_PARAM_CHANGE, NULL)) {
        av_frame_unref(s->last_frame);
        av_frame_unref(s->second_last_frame);
    if (buf_size < 8)
        return AVERROR_INVALIDDATA;
    frame_format         = AV_RL8(buf);
    send_buffer          = AV_RL8(buf + 1);
    video_data_size      = AV_RL16(buf + 2);
    s->decoding_map_size = AV_RL16(buf + 4);
    s->skip_map_size     = AV_RL16(buf + 6);
    switch(frame_format) {
        case 0x06:
            if (s->decoding_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Decoding map for format 0x06\n");
                return AVERROR_INVALIDDATA;
            if (s->skip_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x06\n");
                return AVERROR_INVALIDDATA;
            if (s->is_16bpp) {
                av_log(avctx, AV_LOG_ERROR, "Video format 0x06 does not support 16bpp movies\n");
                return AVERROR_INVALIDDATA;
            /* Decoding map for 0x06 frame format is at the top of pixeldata */
            s->decoding_map_size = ((s->avctx->width / 8) * (s->avctx->height / 8)) * 2;
            s->decoding_map = buf + 8 + 14; /* 14 bits of op data */
            video_data_size -= s->decoding_map_size + 14;
            if (video_data_size <= 0)
                return AVERROR_INVALIDDATA;
            if (buf_size < 8 + s->decoding_map_size + 14 + video_data_size)
                return AVERROR_INVALIDDATA;
            bytestream2_init(&s->stream_ptr, buf + 8 + s->decoding_map_size + 14, video_data_size);
            break;
        case 0x10:
            if (! s->decoding_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x10\n");
                return AVERROR_INVALIDDATA;
            if (! s->skip_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Empty skip map for format 0x10\n");
                return AVERROR_INVALIDDATA;
            if (s->is_16bpp) {
                av_log(avctx, AV_LOG_ERROR, "Video format 0x10 does not support 16bpp movies\n");
                return AVERROR_INVALIDDATA;
            if (buf_size < 8 + video_data_size + s->decoding_map_size + s->skip_map_size)
                return AVERROR_INVALIDDATA;
            bytestream2_init(&s->stream_ptr, buf + 8, video_data_size);
            s->decoding_map = buf + 8 + video_data_size;
            s->skip_map = buf + 8 + video_data_size + s->decoding_map_size;
            break;
        case 0x11:
            if (! s->decoding_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Empty decoding map for format 0x11\n");
                return AVERROR_INVALIDDATA;
            if (s->skip_map_size) {
                av_log(avctx, AV_LOG_ERROR, "Skip map for format 0x11\n");
                return AVERROR_INVALIDDATA;
            if (buf_size < 8 + video_data_size + s->decoding_map_size)
                return AVERROR_INVALIDDATA;
            bytestream2_init(&s->stream_ptr, buf + 8, video_data_size);
            s->decoding_map = buf + 8 + video_data_size;
            break;
        default:
            av_log(avctx, AV_LOG_ERROR, "Frame type 0x%02X unsupported\n", frame_format);
    /* ensure we can't overread the packet */
    if (buf_size < 8 + s->decoding_map_size + video_data_size + s->skip_map_size) {
        av_log(avctx, AV_LOG_ERROR, "Invalid IP packet size\n");
        return AVERROR_INVALIDDATA;
    if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0)
    if (!s->is_16bpp) {
        int size;
        const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &size);
        if (pal && size == AVPALETTE_SIZE) {
            frame->palette_has_changed = 1;
            memcpy(s->pal, pal, AVPALETTE_SIZE);
        } else if (pal) {
            av_log(avctx, AV_LOG_ERROR, "Palette size %d is wrong\n", size);
    switch(frame_format) {
        case 0x06:
            ipvideo_decode_format_06_opcodes(s, frame);
            break;
        case 0x10:
            ipvideo_decode_format_10_opcodes(s, frame);
            break;
        case 0x11:
            ipvideo_decode_format_11_opcodes(s, frame);
            break;
    *got_frame = send_buffer;
    /* shuffle frames */
    av_frame_unref(s->second_last_frame);
    FFSWAP(AVFrame*, s->second_last_frame, s->last_frame);
    if ((ret = av_frame_ref(s->last_frame, frame)) < 0)
    /* report that the buffer was completely consumed */
    return buf_size;


static int qio_channel_websock_handshake_process(QIOChannelWebsock *ioc,

                                                 char *buffer,

                                                 Error **errp)

{

    QIOChannelWebsockHTTPHeader hdrs[32];

    size_t nhdrs = G_N_ELEMENTS(hdrs);

    const char *protocols = NULL, *version = NULL, *key = NULL,

        *host = NULL, *connection = NULL, *upgrade = NULL;

    nhdrs = qio_channel_websock_extract_headers(buffer, hdrs, nhdrs, errp);

    if (!nhdrs) {

        return -1;

    }

    protocols = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_PROTOCOL);

    if (!protocols) {

        error_setg(errp, "Missing websocket protocol header data");

        return -1;

    }

    version = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_VERSION);

    if (!version) {

        error_setg(errp, "Missing websocket version header data");

        return -1;

    }

    key = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_KEY);

    if (!key) {

        error_setg(errp, "Missing websocket key header data");

        return -1;

    }

    host = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_HOST);

    if (!host) {

        error_setg(errp, "Missing websocket host header data");

        return -1;

    }

    connection = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_CONNECTION);

    if (!connection) {

        error_setg(errp, "Missing websocket connection header data");

        return -1;

    }

    upgrade = qio_channel_websock_find_header(

        hdrs, nhdrs, QIO_CHANNEL_WEBSOCK_HEADER_UPGRADE);

    if (!upgrade) {

        error_setg(errp, "Missing websocket upgrade header data");

        return -1;

    }

    if (!g_strrstr(protocols, QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY)) {

        error_setg(errp, "No '%s' protocol is supported by client '%s'",

                   QIO_CHANNEL_WEBSOCK_PROTOCOL_BINARY, protocols);

        return -1;

    }

    if (!g_str_equal(version, QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION)) {

        error_setg(errp, "Version '%s' is not supported by client '%s'",

                   QIO_CHANNEL_WEBSOCK_SUPPORTED_VERSION, version);

        return -1;

    }

    if (strlen(key) != QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN) {

        error_setg(errp, "Key length '%zu' was not as expected '%d'",

                   strlen(key), QIO_CHANNEL_WEBSOCK_CLIENT_KEY_LEN);

        return -1;

    }

    if (!g_strrstr(connection, QIO_CHANNEL_WEBSOCK_CONNECTION_UPGRADE)) {

        error_setg(errp, "No connection upgrade requested '%s'", connection);

        return -1;

    }

    if (!g_str_equal(upgrade, QIO_CHANNEL_WEBSOCK_UPGRADE_WEBSOCKET)) {

        error_setg(errp, "Incorrect upgrade method '%s'", upgrade);

        return -1;

    }

    return qio_channel_websock_handshake_send_response(ioc, key, errp);

}


int attribute_align_arg avcodec_decode_audio3(AVCodecContext *avctx, int16_t *samples,

                                              int *frame_size_ptr,

                                              AVPacket *avpkt)

{

    AVFrame frame;

    int ret, got_frame = 0;

    if (avctx->get_buffer != avcodec_default_get_buffer) {

        av_log(avctx, AV_LOG_ERROR, "Custom get_buffer() for use with"

                                    "avcodec_decode_audio3() detected. Overriding with avcodec_default_get_buffer\n");

        av_log(avctx, AV_LOG_ERROR, "Please port your application to "

                                    "avcodec_decode_audio4()\n");

        avctx->get_buffer = avcodec_default_get_buffer;

    }

    ret = avcodec_decode_audio4(avctx, &frame, &got_frame, avpkt);

    if (ret >= 0 && got_frame) {

        int ch, plane_size;

        int planar    = av_sample_fmt_is_planar(avctx->sample_fmt);

        int data_size = av_samples_get_buffer_size(&plane_size, avctx->channels,

                                                   frame.nb_samples,

                                                   avctx->sample_fmt, 1);

        if (*frame_size_ptr < data_size) {

            av_log(avctx, AV_LOG_ERROR, "output buffer size is too small for "

                                        "the current frame (%d < %d)\n", *frame_size_ptr, data_size);

            return AVERROR(EINVAL);

        }

        memcpy(samples, frame.extended_data[0], plane_size);

        if (planar && avctx->channels > 1) {

            uint8_t *out = ((uint8_t *)samples) + plane_size;

            for (ch = 1; ch < avctx->channels; ch++) {

                memcpy(out, frame.extended_data[ch], plane_size);

                out += plane_size;

            }

        }

        *frame_size_ptr = data_size;

    } else {

        *frame_size_ptr = 0;

    }

    return ret;

}


void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src,

                                 ptrdiff_t stride)

{

    avc_luma_vt_16w_msa(src - (stride * 2), stride, dst, stride, 16);

}


int img_convert(AVPicture *dst, int dst_pix_fmt,

                AVPicture *src, int src_pix_fmt,

                int src_width, int src_height)

{

    static int inited;

    int i, ret, dst_width, dst_height, int_pix_fmt;

    PixFmtInfo *src_pix, *dst_pix;

    ConvertEntry *ce;

    AVPicture tmp1, *tmp = &tmp1;

    if (src_pix_fmt < 0 || src_pix_fmt >= PIX_FMT_NB ||

        dst_pix_fmt < 0 || dst_pix_fmt >= PIX_FMT_NB)

        return -1;

    if (src_width <= 0 || src_height <= 0)

        return 0;

    if (!inited) {

        inited = 1;

        img_convert_init();

    }

    dst_width = src_width;

    dst_height = src_height;

    dst_pix = &pix_fmt_info[dst_pix_fmt];

    src_pix = &pix_fmt_info[src_pix_fmt];

    if (src_pix_fmt == dst_pix_fmt) {

        /* XXX: incorrect */

        /* same format: just copy */

        for(i = 0; i < dst_pix->nb_components; i++) {

            int w, h;

            w = dst_width;

            h = dst_height;

            if (is_yuv_planar(dst_pix) && (i == 1 || i == 2)) {

                w >>= dst_pix->x_chroma_shift;

                h >>= dst_pix->y_chroma_shift;

            }

            img_copy(dst->data[i], dst->linesize[i],

                     src->data[i], src->linesize[i],

                     w, h);

        }

        return 0;

    }

    ce = &convert_table[src_pix_fmt][dst_pix_fmt];

    if (ce->convert) {

        /* specific convertion routine */

        ce->convert(dst, src, dst_width, dst_height);

        return 0;

    }

    /* gray to YUV */

    if (is_yuv_planar(dst_pix) &&

        src_pix_fmt == PIX_FMT_GRAY8) {

        int w, h, y;

        uint8_t *d;

        if (dst_pix->color_type == FF_COLOR_YUV_JPEG) {

            img_copy(dst->data[0], dst->linesize[0],

                     src->data[0], src->linesize[0],

                     dst_width, dst_height);

        } else {

            img_apply_table(dst->data[0], dst->linesize[0],

                            src->data[0], src->linesize[0],

                            dst_width, dst_height,

                            y_jpeg_to_ccir);

        }

        /* fill U and V with 128 */

        w = dst_width;

        h = dst_height;

        w >>= dst_pix->x_chroma_shift;

        h >>= dst_pix->y_chroma_shift;

        for(i = 1; i <= 2; i++) {

            d = dst->data[i];

            for(y = 0; y< h; y++) {

                memset(d, 128, w);

                d += dst->linesize[i];

            }

        }

        return 0;

    }

    /* YUV to gray */

    if (is_yuv_planar(src_pix) &&

        dst_pix_fmt == PIX_FMT_GRAY8) {

        if (src_pix->color_type == FF_COLOR_YUV_JPEG) {

            img_copy(dst->data[0], dst->linesize[0],

                     src->data[0], src->linesize[0],

                     dst_width, dst_height);

        } else {

            img_apply_table(dst->data[0], dst->linesize[0],

                            src->data[0], src->linesize[0],

                            dst_width, dst_height,

                            y_ccir_to_jpeg);

        }

        return 0;

    }

    /* YUV to YUV planar */

    if (is_yuv_planar(dst_pix) && is_yuv_planar(src_pix)) {

        int x_shift, y_shift, w, h;

        void (*resize_func)(uint8_t *dst, int dst_wrap,

                            uint8_t *src, int src_wrap,

                            int width, int height);

        /* compute chroma size of the smallest dimensions */

        w = dst_width;

        h = dst_height;

        if (dst_pix->x_chroma_shift >= src_pix->x_chroma_shift)

            w >>= dst_pix->x_chroma_shift;

        else

            w >>= src_pix->x_chroma_shift;

        if (dst_pix->y_chroma_shift >= src_pix->y_chroma_shift)

            h >>= dst_pix->y_chroma_shift;

        else

            h >>= src_pix->y_chroma_shift;

        x_shift = (dst_pix->x_chroma_shift - src_pix->x_chroma_shift);

        y_shift = (dst_pix->y_chroma_shift - src_pix->y_chroma_shift);

        if (x_shift == 0 && y_shift == 0) {

            resize_func = img_copy;

        } else if (x_shift == 0 && y_shift == 1) {

            resize_func = shrink2;

        } else if (x_shift == 1 && y_shift == 1) {

            resize_func = shrink22;

        } else if (x_shift == -1 && y_shift == -1) {

            resize_func = grow22;

        } else if (x_shift == -1 && y_shift == 1) {

            resize_func = conv411;

        } else {

            /* currently not handled */

            return -1;

        }

        img_copy(dst->data[0], dst->linesize[0],

                 src->data[0], src->linesize[0],

                 dst_width, dst_height);

        for(i = 1;i <= 2; i++)

            resize_func(dst->data[i], dst->linesize[i],

                        src->data[i], src->linesize[i],

                        dst_width>>dst_pix->x_chroma_shift, dst_height>>dst_pix->y_chroma_shift);

        /* if yuv color space conversion is needed, we do it here on

           the destination image */

        if (dst_pix->color_type != src_pix->color_type) {

            const uint8_t *y_table, *c_table;

            if (dst_pix->color_type == FF_COLOR_YUV) {

                y_table = y_jpeg_to_ccir;

                c_table = c_jpeg_to_ccir;

            } else {

                y_table = y_ccir_to_jpeg;

                c_table = c_ccir_to_jpeg;

            }

            img_apply_table(dst->data[0], dst->linesize[0],

                            dst->data[0], dst->linesize[0],

                            dst_width, dst_height,

                            y_table);

            for(i = 1;i <= 2; i++)

                img_apply_table(dst->data[i], dst->linesize[i],

                                dst->data[i], dst->linesize[i],

                                dst_width>>dst_pix->x_chroma_shift,

                                dst_height>>dst_pix->y_chroma_shift,

                                c_table);

        }

        return 0;

    }

    /* try to use an intermediate format */

    if (src_pix_fmt == PIX_FMT_YUV422 ||

        dst_pix_fmt == PIX_FMT_YUV422) {

        /* specific case: convert to YUV422P first */

        int_pix_fmt = PIX_FMT_YUV422P;

    } else if ((src_pix->color_type == FF_COLOR_GRAY &&

                src_pix_fmt != PIX_FMT_GRAY8) ||

               (dst_pix->color_type == FF_COLOR_GRAY &&

                dst_pix_fmt != PIX_FMT_GRAY8)) {

        /* gray8 is the normalized format */

        int_pix_fmt = PIX_FMT_GRAY8;

    } else if ((is_yuv_planar(src_pix) &&

                src_pix_fmt != PIX_FMT_YUV444P &&

                src_pix_fmt != PIX_FMT_YUVJ444P)) {

        /* yuv444 is the normalized format */

        if (src_pix->color_type == FF_COLOR_YUV_JPEG)

            int_pix_fmt = PIX_FMT_YUVJ444P;

        else

            int_pix_fmt = PIX_FMT_YUV444P;

    } else if ((is_yuv_planar(dst_pix) &&

                dst_pix_fmt != PIX_FMT_YUV444P &&

                dst_pix_fmt != PIX_FMT_YUVJ444P)) {

        /* yuv444 is the normalized format */

        if (dst_pix->color_type == FF_COLOR_YUV_JPEG)

            int_pix_fmt = PIX_FMT_YUVJ444P;

        else

            int_pix_fmt = PIX_FMT_YUV444P;

    } else {

        /* the two formats are rgb or gray8 or yuv[j]444p */

        if (src_pix->is_alpha && dst_pix->is_alpha)

            int_pix_fmt = PIX_FMT_RGBA32;

        else

            int_pix_fmt = PIX_FMT_RGB24;

    }

    if (avpicture_alloc(tmp, int_pix_fmt, dst_width, dst_height) < 0)

        return -1;

    ret = -1;

    if (img_convert(tmp, int_pix_fmt,

                    src, src_pix_fmt, src_width, src_height) < 0)

        goto fail1;

    if (img_convert(dst, dst_pix_fmt,

                    tmp, int_pix_fmt, dst_width, dst_height) < 0)

        goto fail1;

    ret = 0;

 fail1:

    avpicture_free(tmp);

    return ret;

}


static void render_fragments(Vp3DecodeContext *s,

                             int first_fragment,

                             int fragment_width,

                             int fragment_height,

                             int plane /* 0 = Y, 1 = U, 2 = V */)

{

    int x, y;

    int m, n;

    int i = first_fragment;

    int j;

    int16_t *dequantizer;

    DCTELEM dequant_block[64];

    unsigned char *output_plane;

    unsigned char *last_plane;

    unsigned char *golden_plane;

    int stride;

    debug_vp3("  vp3: rendering final fragments for %s\n",

        (plane == 0) ? "Y plane" : (plane == 1) ? "U plane" : "V plane");

    /* set up plane-specific parameters */

    if (plane == 0) {

        dequantizer = s->intra_y_dequant;

        output_plane = s->current_frame.data[0];

        last_plane = s->current_frame.data[0];

        golden_plane = s->current_frame.data[0];

        stride = -s->current_frame.linesize[0];

    } else if (plane == 1) {

        dequantizer = s->intra_c_dequant;

        output_plane = s->current_frame.data[1];

        last_plane = s->current_frame.data[1];

        golden_plane = s->current_frame.data[1];

        stride = -s->current_frame.linesize[1];

    } else {

        dequantizer = s->intra_c_dequant;

        output_plane = s->current_frame.data[2];

        last_plane = s->current_frame.data[2];

        golden_plane = s->current_frame.data[2];

        stride = -s->current_frame.linesize[2];

    }

    /* for each fragment row... */

    for (y = 0; y < fragment_height; y++) {

        /* for each fragment in a row... */

        for (x = 0; x < fragment_width; x++, i++) {

            /* transform if this block was coded */

            if (s->all_fragments[i].coding_method == MODE_INTRA) {

                /* dequantize the DCT coefficients */

                for (j = 0; j < 64; j++)

                    dequant_block[dequant_index[j]] =

                        s->all_fragments[i].coeffs[j] *

                        dequantizer[j];

                dequant_block[0] += 1024;

                debug_idct("fragment %d:\n", i);

                debug_idct("dequantized block:\n");

                for (m = 0; m < 8; m++) {

                    for (n = 0; n < 8; n++) {

                        debug_idct(" %5d", dequant_block[m * 8 + n]);

                    }

                    debug_idct("\n");

                }

                debug_idct("\n");

                /* invert DCT and place in final output */

                s->dsp.idct_put(

                    output_plane + s->all_fragments[i].first_pixel,

                    stride, dequant_block);

/*

                debug_idct("idct block:\n");

                for (m = 0; m < 8; m++) {

                    for (n = 0; n < 8; n++) {

                        debug_idct(" %3d", pixels[m * 8 + n]);

                    }

                    debug_idct("\n");

                }

                debug_idct("\n");

*/

            } else if (s->all_fragments[i].coding_method == MODE_COPY) {

                /* copy directly from the previous frame */

                for (m = 0; m < 8; m++)

                    memcpy(

                        output_plane + s->all_fragments[i].first_pixel + stride * m,

                        last_plane + s->all_fragments[i].first_pixel + stride * m,

                        8);

            } else {

                /* carry out the motion compensation */

            }

        }

    }

    emms_c();

}