static Image *decompress_block(Image *orig, unsigned int *Size, ImageInfo *clone_info, ExceptionInfo *exception)
{

Image *image2;
void *cache_block, *decompress_block;
z_stream zip_info;
FILE *mat_file;
size_t magick_size;
size_t extent;
int file;

int status;
int zip_status;
ssize_t TotalSize = 0;

  if(clone_info==NULL) return NULL;
  if(clone_info->file)    /* Close file opened from previous transaction. */
  {
    fclose(clone_info->file);
    clone_info->file = NULL;
    (void) remove_utf8(clone_info->filename);
  }

  cache_block = AcquireQuantumMemory((size_t)(*Size < 16384) ? *Size: 16384,sizeof(unsigned char *));
  if(cache_block==NULL) return NULL;
  decompress_block = AcquireQuantumMemory((size_t)(4096),sizeof(unsigned char *));
  if(decompress_block==NULL)
  {
    RelinquishMagickMemory(cache_block);
    return NULL;
  }

  mat_file=0;
  file = AcquireUniqueFileResource(clone_info->filename);
  if (file != -1)
    mat_file = fdopen(file,"w");
  if(!mat_file)
  {
    RelinquishMagickMemory(cache_block);
    RelinquishMagickMemory(decompress_block);
    (void) LogMagickEvent(CoderEvent,GetMagickModule(),"Cannot create file stream for decompressed image");
    return NULL;
  }

  zip_info.zalloc=AcquireZIPMemory;
  zip_info.zfree=RelinquishZIPMemory;
  zip_info.opaque = (voidpf) NULL;
  zip_status = inflateInit(&zip_info);
  if (zip_status != Z_OK)
    {
      RelinquishMagickMemory(cache_block);
      RelinquishMagickMemory(decompress_block);
      (void) ThrowMagickException(exception,GetMagickModule(),CorruptImageError,
        "UnableToUncompressImage","`%s'",clone_info->filename);
      (void) fclose(mat_file);
      RelinquishUniqueFileResource(clone_info->filename);
      return NULL;
    }
  /* zip_info.next_out = 8*4;*/

  zip_info.avail_in = 0;
  zip_info.total_out = 0;
  while(*Size>0 && !EOFBlob(orig))
  {
    magick_size = ReadBlob(orig, (*Size < 16384) ? *Size : 16384, (unsigned char *) cache_block);
    zip_info.next_in = (Bytef *) cache_block;
    zip_info.avail_in = (uInt) magick_size;

    while(zip_info.avail_in>0)
    {
      zip_info.avail_out = 4096;
      zip_info.next_out = (Bytef *) decompress_block;
      zip_status = inflate(&zip_info,Z_NO_FLUSH);
      if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
        break;
      extent=fwrite(decompress_block, 4096-zip_info.avail_out, 1, mat_file);
      (void) extent;
      TotalSize += 4096-zip_info.avail_out;

      if(zip_status == Z_STREAM_END) goto DblBreak;
    }
    if ((zip_status != Z_OK) && (zip_status != Z_STREAM_END))
      break;

    *Size -= magick_size;
  }
DblBreak:

  inflateEnd(&zip_info);
  (void)fclose(mat_file);
  RelinquishMagickMemory(cache_block);
  RelinquishMagickMemory(decompress_block);
  *Size = TotalSize;

  if((clone_info->file=fopen(clone_info->filename,"rb"))==NULL) goto UnlinkFile;
  if( (image2 = AcquireImage(clone_info,exception))==NULL ) goto EraseFile;
  status = OpenBlob(clone_info,image2,ReadBinaryBlobMode,exception);
  if (status == MagickFalse)
  {
    DeleteImageFromList(&image2);
EraseFile:
    fclose(clone_info->file);
    clone_info->file = NULL;
UnlinkFile:
    RelinquishUniqueFileResource(clone_info->filename);
    return NULL;
  }

  return image2;
}


QPDF::CopiedStreamDataProvider::provideStreamData(
    int objid, int generation, Pipeline* pipeline)
{
    QPDFObjectHandle foreign_stream =
        this->foreign_streams[QPDFObjGen(objid, generation)];
    foreign_stream.pipeStreamData(pipeline, false, false, false);
}


QPDF::pipeStreamData(int objid, int generation,
		     qpdf_offset_t offset, size_t length,
		     QPDFObjectHandle stream_dict,
		     Pipeline* pipeline)
{
    std::vector<PointerHolder<Pipeline> > to_delete;
    if (this->encrypted)
    {
	decryptStream(pipeline, objid, generation, stream_dict, to_delete);
    }

    try
    {
	this->file->seek(offset, SEEK_SET);
	char buf[10240];
	while (length > 0)
	{
	    size_t to_read = (sizeof(buf) < length ? sizeof(buf) : length);
	    size_t len = this->file->read(buf, to_read);
	    if (len == 0)
	    {
		throw QPDFExc(qpdf_e_damaged_pdf,
			      this->file->getName(),
			      this->last_object_description,
			      this->file->getLastOffset(),
			      "unexpected EOF reading stream data");
	    }
	    length -= len;
	    pipeline->write(QUtil::unsigned_char_pointer(buf), len);
	}
    }
    catch (QPDFExc& e)
    {
	warn(e);
    }
    catch (std::runtime_error& e)
    {
	QTC::TC("qpdf", "QPDF decoding error warning");
	warn(QPDFExc(qpdf_e_damaged_pdf, this->file->getName(),
		     "", this->file->getLastOffset(),
		     "error decoding stream data for object " +
		     QUtil::int_to_string(objid) + " " +
		     QUtil::int_to_string(generation) + ": " + e.what()));
    }
    pipeline->finish();
}


QPDF::replaceObject(int objid, int generation, QPDFObjectHandle oh)
{
    if (oh.isIndirect())
    {
	QTC::TC("qpdf", "QPDF replaceObject called with indirect object");
	throw std::logic_error(
	    "QPDF::replaceObject called with indirect object handle");
    }

    // Force new object to appear in the cache
    resolve(objid, generation);

    // Replace the object in the object cache
    QPDFObjGen og(objid, generation);
    this->obj_cache[og] =
	ObjCache(QPDFObjectHandle::ObjAccessor::getObject(oh), -1, -1);
}


QPDF::~QPDF()
{
    // If two objects are mutually referential (through each object
    // having an array or dictionary that contains an indirect
    // reference to the other), the circular references in the
    // PointerHolder objects will prevent the objects from being
    // deleted.  Walk through all objects in the object cache, which
    // is those objects that we read from the file, and break all
    // resolved references.  At this point, obviously no one is still
    // using the QPDF object, but we'll explicitly clear the xref
    // table anyway just to prevent any possibility of resolve()
    // succeeding.  Note that we can't break references like this at
    // any time when the QPDF object is active.  If we do, the next
    // reference will reread the object from the file, which would
    // have the effect of undoing any modifications that may have been
    // made to any of the objects.
    this->xref_table.clear();
    for (std::map<QPDFObjGen, ObjCache>::iterator iter =
             this->obj_cache.begin();
	 iter != obj_cache.end(); ++iter)
    {
	QPDFObject::ObjAccessor::releaseResolved(
	    (*iter).second.object.getPointer());
    }
}


QPDF::copyForeignObject(QPDFObjectHandle foreign)
{
    return copyForeignObject(foreign, false);
}


QPDFObjectHandle::assertName()
{
    assertType("Name", isName());
}


QPDFObjectHandle::assertString()
{
    assertType("String", isString());
}


QPDFObjectHandle::getTypeCode()
{
    if (this->initialized)
    {
        dereference();
        return obj->getTypeCode();
    }
    else
    {
        return QPDFObject::ot_uninitialized;
    }
}


QPDFObjectHandle::getTypeName()
{
    if (this->initialized)
    {
        dereference();
        return obj->getTypeName();
    }
    else
    {
        return "uninitialized";
    }
}


QPDFObjectHandle::newReal(std::string const& value)
{
    return QPDFObjectHandle(new QPDF_Real(value));
}


QPDFObjectHandle::newInlineImage(std::string const& value)
{
    return QPDFObjectHandle(new QPDF_InlineImage(value));
}


QPDFObjectHandle::setArrayFromVector(std::vector<QPDFObjectHandle> const& items)
{
    assertArray();
    return dynamic_cast<QPDF_Array*>(obj.getPointer())->setFromVector(items);
}


QPDFObjectHandle::assertBool()
{
    assertType("Boolean", isBool());
}


QPDFObjectHandle::newReal(double value, int decimal_places)
{
    return QPDFObjectHandle(new QPDF_Real(value, decimal_places));
}


QPDFObjectHandle::getBoolValue()
{
    assertBool();
    return dynamic_cast<QPDF_Bool*>(obj.getPointer())->getVal();
}


QPDFObjectHandle::getObjGen() const
{
    return QPDFObjGen(this->objid, this->generation);
}


QPDFObjectHandle::getObjectID() const
{
    return this->objid;
}


QPDFObjectHandle::newName(std::string const& name)
{
    return QPDFObjectHandle(new QPDF_Name(name));
}


QPDFObjectHandle::unparseResolved()
{
    if (this->reserved)
    {
        throw std::logic_error(
            "QPDFObjectHandle: attempting to unparse a reserved object");
    }
    dereference();
    return this->obj->unparse();
}


QPDFObjectHandle::getGeneration() const
{
    return this->generation;
}


QPDFObjectHandle::newInteger(long long value)
{
    return QPDFObjectHandle(new QPDF_Integer(value));
}


xps_load_sfnt_cmap(xps_font_t *font)
{
    byte *cmapdata;
    int offset, length;
    int nsubtables;

    offset = xps_find_sfnt_table(font, "cmap", &length);
    if (offset < 0 || length < 4)
    {
        gs_warn("cannot find cmap table");
        return;
    }

    cmapdata = font->data + offset;

    nsubtables = u16(cmapdata + 2);
    if (nsubtables < 0 || length < 4 + nsubtables * 8)
    {
        gs_warn("cannot find cmap sub-tables");
        return;
    }

    font->cmaptable = offset;
    font->cmapsubcount = nsubtables;
    font->cmapsubtable = 0;
}


xps_measure_font_glyph(xps_context_t *ctx, xps_font_t *font, int gid, xps_glyph_metrics_t *mtx)
{

    int head, format, loca, glyf;
    int ofs, len;
    int idx, i, n;
    int hadv, vadv, vorg;
    int vtop, ymax, desc;
    int scale;

    /* some insane defaults */

    scale = 1000; /* units-per-em */
    hadv = 500;
    vadv = -1000;
    vorg = 1000;

    /*
     * Horizontal metrics are easy.
     */

    ofs = xps_find_sfnt_table(font, "hhea", &len);
    if (ofs < 0 || len < 2 * 18)
    {
        gs_warn("hhea table is too short");
        return;
    }

    vorg = s16(font->data + ofs + 4); /* ascender is default vorg */
    desc = s16(font->data + ofs + 6); /* descender */
    if (desc < 0)
        desc = -desc;
    n = u16(font->data + ofs + 17 * 2);

    ofs = xps_find_sfnt_table(font, "hmtx", &len);
    if (ofs < 0)
    {
        gs_warn("cannot find hmtx table");
        return;
    }

    idx = gid;
    if (idx > n - 1)
        idx = n - 1;

    hadv = u16(font->data + ofs + idx * 4);
    vadv = 0;

    /*
     * Vertical metrics are hairy (with missing tables).
     */

    head = xps_find_sfnt_table(font, "head", &len);
    if (head > 0)
    {
        scale = u16(font->data + head + 18); /* units per em */
    }

    ofs = xps_find_sfnt_table(font, "OS/2", &len);
    if (ofs > 0 && len > 70)
    {
        vorg = s16(font->data + ofs + 68); /* sTypoAscender */
        desc = s16(font->data + ofs + 70); /* sTypoDescender */
        if (desc < 0)
            desc = -desc;
    }

    ofs = xps_find_sfnt_table(font, "vhea", &len);
    if (ofs > 0 && len >= 2 * 18)
    {
        n = u16(font->data + ofs + 17 * 2);

        ofs = xps_find_sfnt_table(font, "vmtx", &len);
        if (ofs < 0)
        {
            gs_warn("cannot find vmtx table");
            return;
        }

        idx = gid;
        if (idx > n - 1)
            idx = n - 1;

        vadv = u16(font->data + ofs + idx * 4);
        vtop = u16(font->data + ofs + idx * 4 + 2);

        glyf = xps_find_sfnt_table(font, "glyf", &len);
        loca = xps_find_sfnt_table(font, "loca", &len);
        if (head > 0 && glyf > 0 && loca > 0)
        {
            format = u16(font->data + head + 50); /* indexToLocaFormat */

            if (format == 0)
                ofs = u16(font->data + loca + gid * 2) * 2;
            else
                ofs = u32(font->data + loca + gid * 4);

            ymax = u16(font->data + glyf + ofs + 8); /* yMax */

            vorg = ymax + vtop;
        }
    }

    ofs = xps_find_sfnt_table(font, "VORG", &len);
    if (ofs > 0)
    {
        vorg = u16(font->data + ofs + 6);
        n = u16(font->data + ofs + 6);
        for (i = 0; i < n; i++)
        {
            if (u16(font->data + ofs + 8 + 4 * i) == gid)
            {
                vorg = s16(font->data + ofs + 8 + 4 * i + 2);
                break;
            }
        }
    }

    if (vadv == 0)
        vadv = vorg + desc;

    mtx->hadv = hadv / (float) scale;
    mtx->vadv = vadv / (float) scale;
    mtx->vorg = vorg / (float) scale;
}


  static void  Move_CVT( EXEC_OPS  Int index, TT_F26Dot6 value )
  {
    int ov=CUR.cvt[index];
    (void)ov; /* Quiet compiler warning in release build. */
    CUR.cvt[index] += value;
    DBG_PRINT3(" cvt[%d]%d:=%d", index, ov, CUR.cvt[index]);
  }


  static void  Ins_CALL( INS_ARG )
  {
    PCallRecord  pCrec;

    if ( BOUNDS( args[0], CUR.numFDefs ) || !CUR.FDefs[args[0]].Active )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( CUR.callTop >= CUR.callSize )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    DBG_PRINT1("%d", args[0]);

    pCrec = &CUR.callStack[CUR.callTop];

    pCrec->Caller_Range = CUR.curRange;
    pCrec->Caller_IP    = CUR.IP + 1;
    pCrec->Cur_Count    = 1;
    pCrec->Cur_Restart  = CUR.FDefs[args[0]].Start;

    CUR.callTop++;

    INS_Goto_CodeRange( CUR.FDefs[args[0]].Range,
                        CUR.FDefs[args[0]].Start );

    CUR.step_ins = FALSE;
  }


  static void  Ins_ABS( INS_ARG )
  { (void)exc;
    args[0] = ABS( args[0] );
  }


  static void  Ins_PUSHB( INS_ARG )
  {
    Int  L, K;

    L = ((Int)CUR.opcode - 0xB0 + 1);

    if ( BOUNDS( L, CUR.stackSize+1-CUR.top ) )
    {
      CUR.error = TT_Err_Stack_Overflow;
      return;
    }

    for ( K = 1; K <= L; K++ )
      { args[K - 1] = CUR.code[CUR.IP + K];
        DBG_PRINT1(" %d", args[K - 1]);
      }
  }


  static void  Ins_SDB( INS_ARG )
  {
    CUR.GS.delta_base = (Int)args[0];
  }


  static void  Ins_EVEN( INS_ARG )
  {
    if ( (CUR_Func_round( args[0], 0L ) & 127) == 0 )
      args[0] = 1;
    else
      args[0] = 0;
  }


  static void  Ins_S45ROUND( INS_ARG )
  {
    SET_SuperRound( 0x2D41L, args[0] );
    CUR.GS.round_state = TT_Round_Super_45;

    CUR.func_round = (TRound_Function)Round_Super_45;
  }


  static void  Ins_SHZ( INS_ARG )
  {
    TGlyph_Zone zp;
    Int         refp;
    TT_F26Dot6  dx,
                dy;

    Int  last_point;
    Long i;

    if ( BOUNDS( args[0], 2 ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    if ( COMPUTE_Point_Displacement( &dx, &dy, &zp, &refp ) )
      return;

    last_point = zp.n_points - 1;

    /* undocumented: SHZ doesn't touch the points */
    for ( i = 0; i <= last_point; i++ )
    {
      if ( zp.cur_x != CUR.zp2.cur_x || refp != i )
        MOVE_Zp2_Point( i, dx, dy, FALSE );
    }
  }


  static void  Ins_ALIGNPTS( INS_ARG )
  {
    Int         p1, p2;
    TT_F26Dot6  distance;

    p1 = (Int)args[0];
   p2 = (Int)args[1];

    if ( BOUNDS( args[0], CUR.zp1.n_points ) ||
         BOUNDS( args[1], CUR.zp0.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    distance = CUR_Func_project( CUR.zp0.cur_x[p2] -
                                   CUR.zp1.cur_x[p1],
                                 CUR.zp0.cur_y[p2] -
                                   CUR.zp1.cur_y[p1] ) / 2;

    CUR_Func_move( &CUR.zp1, p1, distance );

    CUR_Func_move( &CUR.zp0, p2, -distance );
  }


  static void  Ins_UTP( INS_ARG )
  {
    Byte  mask;

    if ( BOUNDS( args[0], CUR.zp0.n_points ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    mask = 0xFF;

    if ( CUR.GS.freeVector.x != 0 )
      mask &= ~TT_Flag_Touched_X;

    if ( CUR.GS.freeVector.y != 0 )
      mask &= ~TT_Flag_Touched_Y;

    CUR.zp0.touch[args[0]] &= mask;
  }


  static void  Ins_IUP( INS_ARG )
  {
    struct LOC_Ins_IUP  V;
    unsigned char       mask;

    Long first_point;   /* first point of contour        */
    Long end_point;     /* end point (last+1) of contour */

    Long first_touched; /* first touched point in contour   */
    Long cur_touched;   /* current touched point in contour */

    Long point;         /* current point   */
    Long contour;       /* current contour */
    (void)args;

    if ( CUR.opcode & 1 )
    {
      mask   = TT_Flag_Touched_X;
      V.orgs = CUR.pts.org_x;
      V.curs = CUR.pts.cur_x;
    }
    else
    {
      mask   = TT_Flag_Touched_Y;
      V.orgs = CUR.pts.org_y;
      V.curs = CUR.pts.cur_y;
    }

    contour = 0;
    point   = 0;

    do
    {
      end_point   = CUR.pts.contours[contour];
      first_point = point;

      while ( point <= end_point && (CUR.pts.touch[point] & mask) == 0 )
        point++;

      if ( point <= end_point )
      {
        first_touched = point;
        cur_touched   = point;

        point++;

        while ( point <= end_point )
        {
          if ( (CUR.pts.touch[point] & mask) != 0 )
          {
            Interp( (Int)(cur_touched + 1),
                    (Int)(point - 1),
                    (Int)cur_touched,
                    (Int)point,
                    &V );
            cur_touched = point;
          }

          point++;
        }

        if ( cur_touched == first_touched )
          Shift( (Int)first_point, (Int)end_point, (Int)cur_touched, &V );
        else
        {
          Interp((Int)(cur_touched + 1),
                 (Int)(end_point),
                 (Int)(cur_touched),
                 (Int)(first_touched),
                 &V );

          Interp((Int)(first_point),
                 (Int)(first_touched - 1),
                 (Int)(cur_touched),
                 (Int)(first_touched),
                 &V );
        }
      }
      contour++;
    } while ( contour < CUR.pts.n_contours );
  }


  static void  Ins_RS( INS_ARG )
  {
    if ( BOUNDS( args[0], CUR.storeSize ) )
    {
      CUR.error = TT_Err_Invalid_Reference;
      return;
    }

    args[0] = CUR.storage[args[0]];
  }


xps_init_truetype_font(xps_context_t *ctx, xps_font_t *font)
{
    int code = 0;

    font->font = (void*) gs_alloc_struct(ctx->memory, gs_font_type42, &st_gs_font_type42, "xps_font type42");
    if (!font->font)
        return gs_throw(gs_error_VMerror, "out of memory");

    /* no shortage of things to initialize */
    {
        gs_font_type42 *p42 = (gs_font_type42*) font->font;

        /* Common to all fonts: */

        p42->next = 0;
        p42->prev = 0;
        p42->memory = ctx->memory;

        p42->dir = ctx->fontdir; /* NB also set by gs_definefont later */
        p42->base = font->font; /* NB also set by gs_definefont later */
        p42->is_resource = false;
        gs_notify_init(&p42->notify_list, gs_memory_stable(ctx->memory));
        p42->id = gs_next_ids(ctx->memory, 1);

        p42->client_data = font; /* that's us */

        /* this is overwritten in grid_fit() */
        gs_make_identity(&p42->FontMatrix);
        gs_make_identity(&p42->orig_FontMatrix); /* NB ... original or zeroes? */

        p42->FontType = ft_TrueType;
        p42->BitmapWidths = false;
        p42->ExactSize = fbit_use_outlines;
        p42->InBetweenSize = fbit_use_outlines;
        p42->TransformedChar = fbit_use_outlines;
        p42->WMode = 0;
        p42->PaintType = 0;
        p42->StrokeWidth = 0;
        p42->is_cached = 0;

        p42->procs.define_font = gs_no_define_font;
        p42->procs.make_font = gs_no_make_font;
        p42->procs.font_info = gs_type42_font_info;
        p42->procs.same_font = gs_default_same_font;
        p42->procs.encode_char = xps_true_callback_encode_char;
        p42->procs.decode_glyph = xps_true_callback_decode_glyph;
        p42->procs.enumerate_glyph = gs_type42_enumerate_glyph;
        p42->procs.glyph_info = gs_type42_glyph_info;
        p42->procs.glyph_outline = gs_type42_glyph_outline;
        p42->procs.glyph_name = xps_true_callback_glyph_name;
        p42->procs.init_fstack = gs_default_init_fstack;
        p42->procs.next_char_glyph = gs_default_next_char_glyph;
        p42->procs.build_char = xps_true_callback_build_char;

        memset(p42->font_name.chars, 0, sizeof(p42->font_name.chars));
        xps_load_sfnt_name(font, (char*)p42->font_name.chars, sizeof(p42->font_name.chars));
        p42->font_name.size = strlen((char*)p42->font_name.chars);

        memset(p42->key_name.chars, 0, sizeof(p42->key_name.chars));
        strcpy((char*)p42->key_name.chars, (char*)p42->font_name.chars);
        p42->key_name.size = strlen((char*)p42->key_name.chars);

        /* Base font specific: */

        p42->FontBBox.p.x = 0;
        p42->FontBBox.p.y = 0;
        p42->FontBBox.q.x = 0;
        p42->FontBBox.q.y = 0;

        uid_set_UniqueID(&p42->UID, p42->id);

        p42->encoding_index = ENCODING_INDEX_UNKNOWN;
        p42->nearest_encoding_index = ENCODING_INDEX_ISOLATIN1;

        p42->FAPI = 0;
        p42->FAPI_font_data = 0;

        /* Type 42 specific: */

        p42->data.string_proc = xps_true_callback_string_proc;
        p42->data.proc_data = font;

        gs_type42_font_init(p42, font->subfontid);
        p42->data.get_glyph_index = xps_true_get_glyph_index;
    }

    if ((code = gs_definefont(ctx->fontdir, font->font)) < 0) {
        return(code);
    }

    code = xps_fapi_passfont (font->font, NULL, NULL, font->data, font->length);
    return code;
}


xps_parse_glyph_metrics(char *s, float *advance, float *uofs, float *vofs, int bidi_level)
{
    s = xps_parse_glyph_advance(s, advance, bidi_level);
    s = xps_parse_glyph_offsets(s, uofs, vofs);
    return s;
}


PreserveTrMode(xps_context_t *ctx)
{

    gs_c_param_list list;
    dev_param_req_t request;
    gs_param_name ParamName = "PreserveTrMode";
    gs_param_typed_value Param;
    char *data;
    gs_gstate *pgs = ctx->pgs;
    int code = 0;

    /* Interrogate the device to see if it supports Text Rendering Mode */
    data = (char *)gs_alloc_bytes(ctx->memory, 15, "temporary special_op string");
    memset(data, 0x00, 15);
    memcpy(data, "PreserveTrMode", 15);
    gs_c_param_list_write(&list, ctx->memory);
    /* Make a null object so that the param list won't check for requests */
    Param.type = gs_param_type_null;
    list.procs->xmit_typed((gs_param_list *)&list, ParamName, &Param);
    /* Stuff the data into a structure for passing to the spec_op */
    request.Param = data;
    request.list = &list;

    code = dev_proc(gs_currentdevice(pgs), dev_spec_op)(gs_currentdevice(pgs), gxdso_get_dev_param,
                                                        &request, sizeof(dev_param_req_t));

    if (code != gs_error_undefined) {
        /* The parameter is present in the device, now we need to see its value */
        gs_c_param_list_read(&list);
        list.procs->xmit_typed((gs_param_list *)&list, ParamName, &Param);

        if (Param.type != gs_param_type_bool) {
            /* This really shoudn't happen, but its best to be sure */
            gs_free_object(ctx->memory, data,"temporary special_op string");
            gs_c_param_list_release(&list);
            return gs_error_typecheck;
        }

        if (Param.value.b) {
            code = 1;
        } else {
            code = 0;
        }
    } else {
        code = 0;
    }
    gs_free_object(ctx->memory, data,"temporary special_op string");
    gs_c_param_list_release(&list);
    return code;
}


void gx_ttfReader__set_font(gx_ttfReader *self, gs_font_type42 *pfont)
{
    self->pfont = pfont;
    self->super.get_metrics = gx_ttfReader__default_get_metrics;
}


static int DebugPrint(ttfFont *ttf, const char *fmt, ...)
{
    char buf[500];
    va_list args;
    int count;

    if (gs_debug_c('Y')) {
        va_start(args, fmt);
        count = vsnprintf(buf, sizeof(buf), fmt, args);
        /* NB: moved debug output from stdout to stderr
         */
        errwrite(ttf->DebugMem, buf, count);
        va_end(args);
    }
    return 0;
}


static void *gx_ttfMemory__alloc_bytes(ttfMemory *self, int size,  const char *cname)
{
    gs_memory_t *mem = ((gx_ttfMemory *)self)->memory;

    return gs_alloc_bytes(mem, size, cname);
}


static void gx_ttfExport__DebugPaint(ttfExport *self)
{
}


static int gx_ttfReader__LoadGlyph(ttfReader *self, int glyph_index, const byte **p, int *size)
{
    gx_ttfReader *r = (gx_ttfReader *)self;
    gs_font_type42 *pfont = r->pfont;
    int code;

    if (r->extra_glyph_index != -1)
        return 0; /* We only maintain a single glyph buffer.
                     It's enough because ttfOutliner__BuildGlyphOutline
                     is optimized for that, and pfont->data.get_outline
                     implements a charstring cache. */
    r->glyph_data.memory = pfont->memory;
    code = pfont->data.get_outline(pfont, (uint)glyph_index, &r->glyph_data);
    r->extra_glyph_index = glyph_index;
    r->pos = 0;
    if (code < 0)
        r->error = code;
    else if (code > 0) {
        /* Should not happen. */
        r->error = gs_note_error(gs_error_unregistered);
    } else {
        *p = r->glyph_data.bits.data;
        *size = r->glyph_data.bits.size;
    }
    return 2; /* found */
}


static void gx_ttfExport__CurveTo(ttfExport *self, FloatPoint *p0, FloatPoint *p1, FloatPoint *p2)
{
    gx_ttfExport *e = (gx_ttfExport *)self;

    if (!e->error) {
        if (e->monotonize) {
            curve_segment s;

            s.notes = sn_none;
            s.p1.x = float2fixed(p0->x), s.p1.y = float2fixed(p0->y),
            s.p2.x = float2fixed(p1->x), s.p2.y = float2fixed(p1->y),
            s.pt.x = float2fixed(p2->x), s.pt.y = float2fixed(p2->y);
            e->error = gx_curve_monotonize(e->path, &s);
        } else
            e->error = gx_path_add_curve_notes(e->path, float2fixed(p0->x), float2fixed(p0->y),
                                     float2fixed(p1->x), float2fixed(p1->y),
                                     float2fixed(p2->x), float2fixed(p2->y), sn_none);
    }
}


int ttfFont__Open_aux(ttfFont *self, ttfInterpreter *tti, gx_ttfReader *r, gs_font_type42 *pfont,
               const gs_matrix * char_tm, const gs_log2_scale_point *log2_scale,
               bool design_grid)
{
    gs_point char_size, subpix_origin;
    gs_matrix post_transform;
    /*
     * Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps,
     * and *pfont already adjusted to it.
     * Therefore TTC headers never comes here.
     */
    unsigned int nTTC = 0;
    bool dg;

    decompose_matrix(pfont, char_tm, log2_scale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
    switch(ttfFont__Open(tti, self, &r->super, nTTC, char_size.x, char_size.y, dg)) {
        case fNoError:
            return 0;
        case fMemoryError:
            return_error(gs_error_VMerror);
        case fUnimplemented:
            return_error(gs_error_unregistered);
        case fBadInstruction:
            WarnBadInstruction(pfont, -1);
            goto recover;
        case fPatented:
            WarnPatented(pfont, self, "The font");
        recover:
            self->patented = true;
            return 0;
        default:
            {	int code = r->super.Error(&r->super);

                if (code < 0)
                    return code;
                return_error(gs_error_invalidfont);
            }
    }
}


int gx_ttf_outline(ttfFont *ttf, gx_ttfReader *r, gs_font_type42 *pfont, int glyph_index,
        const gs_matrix *m, const gs_log2_scale_point *pscale,
        gx_path *path, bool design_grid)
{
    gx_ttfExport e;
    ttfOutliner o;
    gs_point char_size, subpix_origin;
    gs_matrix post_transform;
    /* Ghostscript proceses a TTC index in gs/lib/gs_ttf.ps, */
    /* so that TTC never comes here. */
    FloatMatrix m1;
    bool dg;
    uint gftt = gs_currentgridfittt(pfont->dir);
    bool ttin = (gftt & 1);
    /*	gs_currentgridfittt values (binary) :
        00 - no grid fitting;
        01 - Grid fit with TT interpreter; On failure warn and render unhinted.
        10 - Interpret in the design grid and then autohint.
        11 - Grid fit with TT interpreter; On failure render autohinted.
    */
    bool auth = (gftt & 2);

    decompose_matrix(pfont, m, pscale, design_grid, &char_size, &subpix_origin, &post_transform, &dg);
    m1.a = post_transform.xx;
    m1.b = post_transform.xy;
    m1.c = post_transform.yx;
    m1.d = post_transform.yy;
    m1.tx = post_transform.tx;
    m1.ty = post_transform.ty;
    e.super.bPoints = false;
    e.super.bOutline = true;
    e.super.MoveTo = gx_ttfExport__MoveTo;
    e.super.LineTo = gx_ttfExport__LineTo;
    e.super.CurveTo = gx_ttfExport__CurveTo;
    e.super.Close = gx_ttfExport__Close;
    e.super.Point = gx_ttfExport__Point;
    e.super.SetWidth = gx_ttfExport__SetWidth;
    e.super.DebugPaint = gx_ttfExport__DebugPaint;
    e.error = 0;
    e.path = path;
    e.w.x = 0;
    e.w.y = 0;
    e.monotonize = auth;
    gx_ttfReader__Reset(r);
    ttfOutliner__init(&o, ttf, &r->super, &e.super, true, false, pfont->WMode != 0);
    switch(ttfOutliner__Outline(&o, glyph_index, subpix_origin.x, subpix_origin.y, &m1)) {
        case fBadInstruction:
            WarnBadInstruction(pfont, glyph_index);
            goto recover;
        case fPatented:
            /* The returned outline did not apply a bytecode (it is not grid-fitted). */
            if (!auth)
                WarnPatented(pfont, ttf, "Some glyphs of the font");
        recover :
            if (!design_grid && auth)
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
            /* Falls through. */
        case fNoError:
            if (!design_grid && !ttin && auth)
                return grid_fit(pfont->dir->san, path, pfont, pscale, &e, &o);
            ttfOutliner__DrawGlyphOutline(&o);
            if (e.error)
                return e.error;
            return 0;
        case fMemoryError:
            return_error(gs_error_VMerror);
        case fUnimplemented:
            return_error(gs_error_unregistered);
        default:
            {	int code = r->super.Error(&r->super);

                if (code < 0)
                    return code;
                return_error(gs_error_invalidfont);
            }
    }
}


i_alloc_struct_array(gs_memory_t * mem, uint num_elements,
                     gs_memory_type_ptr_t pstype, client_name_t cname)
{
    gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
    obj_header_t *obj;
    ulong lsize;
#ifdef MEMENTO
    if (Memento_failThisEvent())
        return NULL;
#endif

    ALLOC_CHECK_SIZE(mem,pstype);
#ifdef DEBUG
    if (pstype->enum_ptrs == basic_enum_ptrs) {
        dmprintf2(mem, "  i_alloc_struct_array: called with incorrect structure type (not element), struct='%s', client='%s'\n",
                pstype->sname, cname);
        return NULL;		/* fail */
    }
#endif
    if (alloc_array_check_size(num_elements, pstype->ssize, &lsize) == false)
        return NULL;
    obj = alloc_obj(imem, lsize, pstype, ALLOC_DIRECT, cname);
    if_debug7m('A', mem, "[a%d:+<.]%s %s*(%lu=%u*%u) = 0x%lx\n",
               alloc_trace_space(imem), client_name_string(cname),
               struct_type_name_string(pstype),
               (ulong) num_elements * pstype->ssize,
               num_elements, pstype->ssize, (ulong) obj);
    return (char *)obj;
}


alloc_close_clump(gs_ref_memory_t * mem)
{
#ifdef DEBUG
    if (gs_debug_c('A')) {
        dmlprintf1((const gs_memory_t *)mem, "[a%d]", alloc_trace_space(mem));
        dmprintf_clump((const gs_memory_t *)mem, "closing clump", mem->cc);
    }
#endif
}


alloc_link_clump(clump_t * cp, gs_ref_memory_t * imem)
{
    splay_insert(cp, imem);
    SANITY_CHECK(cp);
}


ialloc_reset(gs_ref_memory_t * mem)
{
    mem->root = 0;
    mem->cc = NULL;
    mem->allocated = 0;
    mem->changes = 0;
    mem->scan_limit = 0;
    mem->total_scanned = 0;
    mem->total_scanned_after_compacting = 0;
    ialloc_reset_free(mem);
}


i_enable_free(gs_memory_t * mem, bool enable)
{
    if (enable)
        mem->procs.free_object = i_free_object,
            mem->procs.free_string = i_free_string;
    else
        mem->procs.free_object = gs_ignore_free_object,
            mem->procs.free_string = gs_ignore_free_string;
}


void sanity_check(clump_t *cp)
{
    sanity_check_rec(cp);
}


i_alloc_bytes_immovable(gs_memory_t * mem, uint size, client_name_t cname)
{
    gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
    obj_header_t *obj;

#ifdef MEMENTO
    if (Memento_failThisEvent())
        return NULL;
#endif

    obj = alloc_obj(imem, size, &st_bytes,
                    ALLOC_IMMOVABLE | ALLOC_DIRECT, cname);
    if (obj == 0)
        return 0;
    alloc_trace("|+b.", imem, cname, NULL, size, obj);
    return (byte *) obj;
}


i_alloc_struct(gs_memory_t * mem, gs_memory_type_ptr_t pstype,
               client_name_t cname)
{
    gs_ref_memory_t * const imem = (gs_ref_memory_t *)mem;
    uint size = pstype->ssize;
    obj_header_t *obj;
    obj_header_t **pfl;

#ifdef MEMENTO
    if (Memento_failThisEvent())
        return NULL;
#endif

    ALLOC_CHECK_SIZE(mem,pstype);
    IF_FREELIST_ALLOC(obj, imem, size, pstype, pfl)
        alloc_trace(":+<f", imem, cname, pstype, size, obj);
    ELSEIF_BIG_FREELIST_ALLOC(obj, imem, size, pstype)
        alloc_trace(":+<F", imem, cname, pstype, size, obj);
    ELSEIF_LIFO_ALLOC(obj, imem, size, pstype)
        alloc_trace(":+< ", imem, cname, pstype, size, obj);
    ELSE_ALLOC
    {
        obj = alloc_obj(imem, size, pstype, 0, cname);
        if (obj == 0)
            return 0;
        alloc_trace(":+<.", imem, cname, pstype, size, obj);
    }
#if IGC_PTR_STABILITY_CHECK
        obj[-1].d.o.space_id = imem->space_id;
#endif
    return obj;
}


ztoken_handle_comment(i_ctx_t *i_ctx_p, scanner_state *sstate,
                      const ref *ptoken, int scan_code,
                      bool save, bool push_file, op_proc_t cont)
{
    const char *proc_name;
    scanner_state *pstate;
    os_ptr op;
    ref *ppcproc;
    int code;

    switch (scan_code) {
    case scan_Comment:
        proc_name = "%ProcessComment";
        break;
    case scan_DSC_Comment:
        proc_name = "%ProcessDSCComment";
        break;
    default:
        return_error(gs_error_Fatal);  /* can't happen */
    }
    /*
     * We can't use check_ostack here, because it returns on overflow.
     */
    /*check_ostack(2);*/
    if (ostop - osp < 2) {
        code = ref_stack_extend(&o_stack, 2);
        if (code < 0)
            return code;
    }
    check_estack(3);
    code = name_enter_string(imemory, proc_name, esp + 3);
    if (code < 0)
        return code;
    if (save) {
        pstate = (scanner_state *)ialloc_struct(scanner_state_dynamic, &st_scanner_state_dynamic,
                               "ztoken_handle_comment");
        if (pstate == 0)
            return_error(gs_error_VMerror);
        ((scanner_state_dynamic *)pstate)->mem = imemory;
        *pstate = *sstate;
    } else
        pstate = sstate;
    /* Save the token now -- it might be on the e-stack. */
    if (!pstate->s_pstack)
        osp[2] = *ptoken;
    /*
     * Push the continuation, scanner state, file, and callout procedure
     * on the e-stack.
     */
    make_op_estack(esp + 1, cont);
    make_istruct(esp + 2, 0, pstate);
    ppcproc = dict_find_name(esp + 3);
    if (ppcproc == 0) {
        /*
         * This can only happen during initialization.
         * Pop the comment string from the o-stack if needed (see below).
         */
        if (pstate->s_pstack)
            --osp;
        esp += 2;               /* do run the continuation */
    } else {
        /*
         * Push the file and comment string on the o-stack.
         * If we were inside { }, the comment string is already on the stack.
         */
        if (pstate->s_pstack) {
            op = ++osp;
            *op = op[-1];
        } else {
            op = osp += 2;
            /* *op = *ptoken; */        /* saved above */
        }
        op[-1] = pstate->s_file;
        esp[3] = *ppcproc;
        esp += 3;
    }
    return o_push_estack;
}


token_continue(i_ctx_t *i_ctx_p, scanner_state * pstate, bool save)
{
    os_ptr op = osp;
    int code;
    ref token;

    /* Since we might free pstate below, and we're dealing with
     * gc memory referenced by the stack, we need to explicitly
     * remove the reference to pstate from the stack, otherwise
     * the garbager will fall over
     */
    make_null(osp);
    /* Note that gs_scan_token may change osp! */
    pop(1);                     /* remove the file or scanner state */
again:
    code = gs_scan_token(i_ctx_p, &token, pstate);
    op = osp;
    switch (code) {
        default:                /* error */
            if (code > 0)       /* comment, not possible */
                code = gs_note_error(gs_error_syntaxerror);
            gs_scanner_error_object(i_ctx_p, pstate, &i_ctx_p->error_object);
            break;
        case scan_BOS:
            code = 0;
        case 0:         /* read a token */
            push(2);
            ref_assign(op - 1, &token);
            make_true(op);
            break;
        case scan_EOF:          /* no tokens */
            push(1);
            make_false(op);
            code = 0;
            break;
        case scan_Refill:       /* need more data */
            code = gs_scan_handle_refill(i_ctx_p, pstate, save,
                                      ztoken_continue);
            switch (code) {
                case 0: /* state is not copied to the heap */
                    goto again;
                case o_push_estack:
                    return code;
            }
            break;              /* error */
    }
    if (code <= 0 && !save) {   /* Deallocate the scanner state record. */
        ifree_object(pstate, "token_continue");
    }
    return code;
}


static int get_bit (byte *fin) {
	int t;
	t = (fin[(bloc>>3)] >> (bloc&7)) & 0x1;
	bloc++;
	return t;
}


void MSG_WriteAngle( msg_t *sb, float f ) {
	MSG_WriteByte (sb, (int)(f*256/360) & 255);
}


void MSG_BeginReadingOOB( msg_t *msg ) {
	msg->readcount = 0;
	msg->bit = 0;
	msg->oob = qtrue;
}


void MSG_Clear( msg_t *buf ) {
	buf->cursize = 0;
	buf->overflowed = qfalse;
	buf->bit = 0;					//<- in bits
}


int commonio_sort_wrt (struct commonio_db *shadow,
                       const struct commonio_db *passwd)
{
	struct commonio_entry *head = NULL, *pw_ptr, *spw_ptr;
	const char *name;

	if ((NULL == shadow) || (NULL == shadow->head)) {
		return 0;
	}

	for (pw_ptr = passwd->head; NULL != pw_ptr; pw_ptr = pw_ptr->next) {
		if (NULL == pw_ptr->eptr) {
			continue;
		}
		name = passwd->ops->getname (pw_ptr->eptr);
		for (spw_ptr = shadow->head;
		     NULL != spw_ptr;
		     spw_ptr = spw_ptr->next) {
			if (NULL == spw_ptr->eptr) {
				continue;
			}
			if (strcmp (name, shadow->ops->getname (spw_ptr->eptr))
			    == 0) {
				break;
			}
		}
		if (NULL == spw_ptr) {
			continue;
		}
		commonio_del_entry (shadow, spw_ptr);
		spw_ptr->next = head;
		head = spw_ptr;
	}

	for (spw_ptr = head; NULL != spw_ptr; spw_ptr = head) {
		head = head->next;

		if (NULL != shadow->head) {
			shadow->head->prev = spw_ptr;
		}
		spw_ptr->next = shadow->head;
		shadow->head = spw_ptr;
	}

	shadow->head->prev = NULL;
	shadow->changed = true;

	return 0;
}


static int default_rebuild_header(struct sk_buff *skb)
{
	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n",
	       skb->dev ? skb->dev->name : "NULL!!!");
	kfree_skb(skb);
	return 1;
}


int register_gifconf(unsigned int family, gifconf_func_t * gifconf)
{
	if (family >= NPROTO)
		return -EINVAL;
	gifconf_list[family] = gifconf;
	return 0;
}


int register_netdevice(struct net_device *dev)
{
	struct hlist_head *head;
	struct hlist_node *p;
	int ret;

	BUG_ON(dev_boot_phase);
	ASSERT_RTNL();

	/* When net_device's are persistent, this will be fatal. */
	BUG_ON(dev->reg_state != NETREG_UNINITIALIZED);

	spin_lock_init(&dev->queue_lock);
	spin_lock_init(&dev->xmit_lock);
	dev->xmit_lock_owner = -1;
#ifdef CONFIG_NET_CLS_ACT
	spin_lock_init(&dev->ingress_lock);
#endif

	ret = alloc_divert_blk(dev);
	if (ret)
		goto out;

	dev->iflink = -1;

	/* Init, if this function is available */
	if (dev->init) {
		ret = dev->init(dev);
		if (ret) {
			if (ret > 0)
				ret = -EIO;
			goto out_err;
		}
	}

	if (!dev_valid_name(dev->name)) {
		ret = -EINVAL;
		goto out_err;
	}

	dev->ifindex = dev_new_index();
	if (dev->iflink == -1)
		dev->iflink = dev->ifindex;

	/* Check for existence of name */
	head = dev_name_hash(dev->name);
	hlist_for_each(p, head) {
		struct net_device *d
			= hlist_entry(p, struct net_device, name_hlist);
		if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
			ret = -EEXIST;
 			goto out_err;
		}
 	}

	/* Fix illegal SG+CSUM combinations. */
	if ((dev->features & NETIF_F_SG) &&
	    !(dev->features & (NETIF_F_IP_CSUM |
			       NETIF_F_NO_CSUM |
			       NETIF_F_HW_CSUM))) {
		printk("%s: Dropping NETIF_F_SG since no checksum feature.\n",
		       dev->name);
		dev->features &= ~NETIF_F_SG;
	}

	/* TSO requires that SG is present as well. */
	if ((dev->features & NETIF_F_TSO) &&
	    !(dev->features & NETIF_F_SG)) {
		printk("%s: Dropping NETIF_F_TSO since no SG feature.\n",
		       dev->name);
		dev->features &= ~NETIF_F_TSO;
	}
	if (dev->features & NETIF_F_UFO) {
		if (!(dev->features & NETIF_F_HW_CSUM)) {
			printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
					"NETIF_F_HW_CSUM feature.\n",
							dev->name);
			dev->features &= ~NETIF_F_UFO;
		}
		if (!(dev->features & NETIF_F_SG)) {
			printk(KERN_ERR "%s: Dropping NETIF_F_UFO since no "
					"NETIF_F_SG feature.\n",
					dev->name);
			dev->features &= ~NETIF_F_UFO;
		}
	}

	/*
	 *	nil rebuild_header routine,
	 *	that should be never called and used as just bug trap.
	 */

	if (!dev->rebuild_header)
		dev->rebuild_header = default_rebuild_header;

	/*
	 *	Default initial state at registry is that the
	 *	device is present.
	 */

	set_bit(__LINK_STATE_PRESENT, &dev->state);

	dev->next = NULL;
	dev_init_scheduler(dev);
	write_lock_bh(&dev_base_lock);
	*dev_tail = dev;
	dev_tail = &dev->next;
	hlist_add_head(&dev->name_hlist, head);
	hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
	dev_hold(dev);
	dev->reg_state = NETREG_REGISTERING;
	write_unlock_bh(&dev_base_lock);

	/* Notify protocols, that a new device appeared. */
	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);

	/* Finish registration after unlock */
	net_set_todo(dev);
	ret = 0;

out:
	return ret;
out_err:
	free_divert_blk(dev);
	goto out;
}


int dev_ioctl(unsigned int cmd, void __user *arg)
{
	struct ifreq ifr;
	int ret;
	char *colon;

	/* One special case: SIOCGIFCONF takes ifconf argument
	   and requires shared lock, because it sleeps writing
	   to user space.
	 */

	if (cmd == SIOCGIFCONF) {
		rtnl_shlock();
		ret = dev_ifconf((char __user *) arg);
		rtnl_shunlock();
		return ret;
	}
	if (cmd == SIOCGIFNAME)
		return dev_ifname((struct ifreq __user *)arg);

	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
		return -EFAULT;

	ifr.ifr_name[IFNAMSIZ-1] = 0;

	colon = strchr(ifr.ifr_name, ':');
	if (colon)
		*colon = 0;

	/*
	 *	See which interface the caller is talking about.
	 */

	switch (cmd) {
		/*
		 *	These ioctl calls:
		 *	- can be done by all.
		 *	- atomic and do not require locking.
		 *	- return a value
		 */
		case SIOCGIFFLAGS:
		case SIOCGIFMETRIC:
		case SIOCGIFMTU:
		case SIOCGIFHWADDR:
		case SIOCGIFSLAVE:
		case SIOCGIFMAP:
		case SIOCGIFINDEX:
		case SIOCGIFTXQLEN:
			dev_load(ifr.ifr_name);
			read_lock(&dev_base_lock);
			ret = dev_ifsioc(&ifr, cmd);
			read_unlock(&dev_base_lock);
			if (!ret) {
				if (colon)
					*colon = ':';
				if (copy_to_user(arg, &ifr,
						 sizeof(struct ifreq)))
					ret = -EFAULT;
			}
			return ret;

		case SIOCETHTOOL:
			dev_load(ifr.ifr_name);
			rtnl_lock();
			ret = dev_ethtool(&ifr);
			rtnl_unlock();
			if (!ret) {
				if (colon)
					*colon = ':';
				if (copy_to_user(arg, &ifr,
						 sizeof(struct ifreq)))
					ret = -EFAULT;
			}
			return ret;

		/*
		 *	These ioctl calls:
		 *	- require superuser power.
		 *	- require strict serialization.
		 *	- return a value
		 */
		case SIOCGMIIPHY:
		case SIOCGMIIREG:
		case SIOCSIFNAME:
			if (!capable(CAP_NET_ADMIN))
				return -EPERM;
			dev_load(ifr.ifr_name);
			rtnl_lock();
			ret = dev_ifsioc(&ifr, cmd);
			rtnl_unlock();
			if (!ret) {
				if (colon)
					*colon = ':';
				if (copy_to_user(arg, &ifr,
						 sizeof(struct ifreq)))
					ret = -EFAULT;
			}
			return ret;

		/*
		 *	These ioctl calls:
		 *	- require superuser power.
		 *	- require strict serialization.
		 *	- do not return a value
		 */
		case SIOCSIFFLAGS:
		case SIOCSIFMETRIC:
		case SIOCSIFMTU:
		case SIOCSIFMAP:
		case SIOCSIFHWADDR:
		case SIOCSIFSLAVE:
		case SIOCADDMULTI:
		case SIOCDELMULTI:
		case SIOCSIFHWBROADCAST:
		case SIOCSIFTXQLEN:
		case SIOCSMIIREG:
		case SIOCBONDENSLAVE:
		case SIOCBONDRELEASE:
		case SIOCBONDSETHWADDR:
		case SIOCBONDSLAVEINFOQUERY:
		case SIOCBONDINFOQUERY:
		case SIOCBONDCHANGEACTIVE:
		case SIOCBRADDIF:
		case SIOCBRDELIF:
			if (!capable(CAP_NET_ADMIN))
				return -EPERM;
			dev_load(ifr.ifr_name);
			rtnl_lock();
			ret = dev_ifsioc(&ifr, cmd);
			rtnl_unlock();
			return ret;

		case SIOCGIFMEM:
			/* Get the per device memory space. We can add this but
			 * currently do not support it */
		case SIOCSIFMEM:
			/* Set the per device memory buffer space.
			 * Not applicable in our case */
		case SIOCSIFLINK:
			return -EINVAL;

		/*
		 *	Unknown or private ioctl.
		 */
		default:
			if (cmd == SIOCWANDEV ||
			    (cmd >= SIOCDEVPRIVATE &&
			     cmd <= SIOCDEVPRIVATE + 15)) {
				dev_load(ifr.ifr_name);
				rtnl_lock();
				ret = dev_ifsioc(&ifr, cmd);
				rtnl_unlock();
				if (!ret && copy_to_user(arg, &ifr,
							 sizeof(struct ifreq)))
					ret = -EFAULT;
				return ret;
			}
#ifdef WIRELESS_EXT
			/* Take care of Wireless Extensions */
			if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) {
				/* If command is `set a parameter', or
				 * `get the encoding parameters', check if
				 * the user has the right to do it */
				if (IW_IS_SET(cmd) || cmd == SIOCGIWENCODE) {
					if (!capable(CAP_NET_ADMIN))
						return -EPERM;
				}
				dev_load(ifr.ifr_name);
				rtnl_lock();
				/* Follow me in net/core/wireless.c */
				ret = wireless_process_ioctl(&ifr, cmd);
				rtnl_unlock();
				if (IW_IS_GET(cmd) &&
				    copy_to_user(arg, &ifr,
					    	 sizeof(struct ifreq)))
					ret = -EFAULT;
				return ret;
			}
#endif	/* WIRELESS_EXT */
			return -EINVAL;
	}
}


int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
{
	int err;

	if (!dev->set_mac_address)
		return -EOPNOTSUPP;
	if (sa->sa_family != dev->type)
		return -EINVAL;
	if (!netif_device_present(dev))
		return -ENODEV;
	err = dev->set_mac_address(dev, sa);
	if (!err)
		notifier_call_chain(&netdev_chain, NETDEV_CHANGEADDR, dev);
	return err;
}


void skb_abort_seq_read(struct skb_seq_state *st)
{
	if (st->frag_data)
		kunmap_skb_frag(st->frag_data);
}


int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
		     gfp_t gfp_mask)
{
	int i;
	u8 *data;
	int size = nhead + (skb->end - skb->head) + ntail;
	long off;

	if (skb_shared(skb))
		BUG();

	size = SKB_DATA_ALIGN(size);

	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
	if (!data)
		goto nodata;

	/* Copy only real data... and, alas, header. This should be
	 * optimized for the cases when header is void. */
	memcpy(data + nhead, skb->head, skb->tail - skb->head);
	memcpy(data + size, skb->end, sizeof(struct skb_shared_info));

	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
		get_page(skb_shinfo(skb)->frags[i].page);

	if (skb_shinfo(skb)->frag_list)
		skb_clone_fraglist(skb);

	skb_release_data(skb);

	off = (data + nhead) - skb->head;

	skb->head     = data;
	skb->end      = data + size;
	skb->data    += off;
	skb->tail    += off;
	skb->mac.raw += off;
	skb->h.raw   += off;
	skb->nh.raw  += off;
	skb->cloned   = 0;
	skb->nohdr    = 0;
	atomic_set(&skb_shinfo(skb)->dataref, 1);
	return 0;

nodata:
	return -ENOMEM;
}


int unregister_netdevice_notifier(struct notifier_block *nb)
{
	return notifier_chain_unregister(&netdev_chain, nb);
}


void *dev_seq_start(struct seq_file *seq, loff_t *pos)
{
	read_lock(&dev_base_lock);
	return *pos ? dev_get_idx(*pos - 1) : SEQ_START_TOKEN;
}


int dev_open(struct net_device *dev)
{
	int ret = 0;

	/*
	 *	Is it already up?
	 */

	if (dev->flags & IFF_UP)
		return 0;

	/*
	 *	Is it even present?
	 */
	if (!netif_device_present(dev))
		return -ENODEV;

	/*
	 *	Call device private open method
	 */
	set_bit(__LINK_STATE_START, &dev->state);
	if (dev->open) {
		ret = dev->open(dev);
		if (ret)
			clear_bit(__LINK_STATE_START, &dev->state);
	}

 	/*
	 *	If it went open OK then:
	 */

	if (!ret) {
		/*
		 *	Set the flags.
		 */
		dev->flags |= IFF_UP;

		/*
		 *	Initialize multicasting status
		 */
		dev_mc_upload(dev);

		/*
		 *	Wakeup transmit queue engine
		 */
		dev_activate(dev);

		/*
		 *	... and announce new interface.
		 */
		notifier_call_chain(&netdev_chain, NETDEV_UP, dev);
	}
	return ret;
}


void dev_seq_stop(struct seq_file *seq, void *v)
{
	read_unlock(&dev_base_lock);
}


static int ethtool_get_link(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_value edata = { ETHTOOL_GLINK };

	if (!dev->ethtool_ops->get_link)
		return -EOPNOTSUPP;

	edata.data = dev->ethtool_ops->get_link(dev);

	if (copy_to_user(useraddr, &edata, sizeof(edata)))
		return -EFAULT;
	return 0;
}


void dev_load(const char *name)
{
	struct net_device *dev;

	read_lock(&dev_base_lock);
	dev = __dev_get_by_name(name);
	read_unlock(&dev_base_lock);

	if (!dev && capable(CAP_SYS_MODULE))
		request_module("%s", name);
}


static void net_rx_action(struct softirq_action *h)
{
	struct softnet_data *queue = &__get_cpu_var(softnet_data);
	unsigned long start_time = jiffies;
	int budget = netdev_budget;
	void *have;

	local_irq_disable();

	while (!list_empty(&queue->poll_list)) {
		struct net_device *dev;

		if (budget <= 0 || jiffies - start_time > 1)
			goto softnet_break;

		local_irq_enable();

		dev = list_entry(queue->poll_list.next,
				 struct net_device, poll_list);
		have = netpoll_poll_lock(dev);

		if (dev->quota <= 0 || dev->poll(dev, &budget)) {
			netpoll_poll_unlock(have);
			local_irq_disable();
			list_del(&dev->poll_list);
			list_add_tail(&dev->poll_list, &queue->poll_list);
			if (dev->quota < 0)
				dev->quota += dev->weight;
			else
				dev->quota = dev->weight;
		} else {
			netpoll_poll_unlock(have);
			dev_put(dev);
			local_irq_disable();
		}
	}
out:
	local_irq_enable();
	return;

softnet_break:
	__get_cpu_var(netdev_rx_stat).time_squeeze++;
	__raise_softirq_irqoff(NET_RX_SOFTIRQ);
	goto out;
}


static int ethtool_get_strings(struct net_device *dev, void __user *useraddr)
{
	struct ethtool_gstrings gstrings;
	struct ethtool_ops *ops = dev->ethtool_ops;
	u8 *data;
	int ret;

	if (!ops->get_strings)
		return -EOPNOTSUPP;

	if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
		return -EFAULT;

	switch (gstrings.string_set) {
	case ETH_SS_TEST:
		if (!ops->self_test_count)
			return -EOPNOTSUPP;
		gstrings.len = ops->self_test_count(dev);
		break;
	case ETH_SS_STATS:
		if (!ops->get_stats_count)
			return -EOPNOTSUPP;
		gstrings.len = ops->get_stats_count(dev);
		break;
	default:
		return -EINVAL;
	}

	data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
	if (!data)
		return -ENOMEM;

	ops->get_strings(dev, gstrings.string_set, data);

	ret = -EFAULT;
	if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
		goto out;
	useraddr += sizeof(gstrings);
	if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
		goto out;
	ret = 0;

 out:
	kfree(data);
	return ret;
}


struct net_device *dev_get_by_index(int ifindex)
{
	struct net_device *dev;

	read_lock(&dev_base_lock);
	dev = __dev_get_by_index(ifindex);
	if (dev)
		dev_hold(dev);
	read_unlock(&dev_base_lock);
	return dev;
}


static int ethtool_get_ufo(struct net_device *dev, char __user *useraddr)
{
	struct ethtool_value edata = { ETHTOOL_GTSO };

	if (!dev->ethtool_ops->get_ufo)
		return -EOPNOTSUPP;
	edata.data = dev->ethtool_ops->get_ufo(dev);
	if (copy_to_user(useraddr, &edata, sizeof(edata)))
		 return -EFAULT;
	return 0;
}


void netdev_state_change(struct net_device *dev)
{
	if (dev->flags & IFF_UP) {
		notifier_call_chain(&netdev_chain, NETDEV_CHANGE, dev);
		rtmsg_ifinfo(RTM_NEWLINK, dev, 0);
	}
}


struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
{
	struct sk_buff *n;

	n = skb + 1;
	if (skb->fclone == SKB_FCLONE_ORIG &&
	    n->fclone == SKB_FCLONE_UNAVAILABLE) {
		atomic_t *fclone_ref = (atomic_t *) (n + 1);
		n->fclone = SKB_FCLONE_CLONE;
		atomic_inc(fclone_ref);
	} else {
		n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
		if (!n)
			return NULL;
		n->fclone = SKB_FCLONE_UNAVAILABLE;
	}

#define C(x) n->x = skb->x

	n->next = n->prev = NULL;
	n->sk = NULL;
	C(tstamp);
	C(dev);
	C(h);
	C(nh);
	C(mac);
	C(dst);
	dst_clone(skb->dst);
	C(sp);
#ifdef CONFIG_INET
	secpath_get(skb->sp);
#endif
	memcpy(n->cb, skb->cb, sizeof(skb->cb));
	C(len);
	C(data_len);
	C(csum);
	C(local_df);
	n->cloned = 1;
	n->nohdr = 0;
	C(pkt_type);
	C(ip_summed);
	C(priority);
	C(protocol);
	n->destructor = NULL;
#ifdef CONFIG_NETFILTER
	C(nfmark);
	C(nfct);
	nf_conntrack_get(skb->nfct);
	C(nfctinfo);
#if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)
	C(ipvs_property);
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
	C(nf_bridge);
	nf_bridge_get(skb->nf_bridge);
#endif
#endif /*CONFIG_NETFILTER*/
#ifdef CONFIG_NET_SCHED
	C(tc_index);
#ifdef CONFIG_NET_CLS_ACT
	n->tc_verd = SET_TC_VERD(skb->tc_verd,0);
	n->tc_verd = CLR_TC_OK2MUNGE(n->tc_verd);
	n->tc_verd = CLR_TC_MUNGED(n->tc_verd);
	C(input_dev);
#endif

#endif
	C(truesize);
	atomic_set(&n->users, 1);
	C(head);
	C(data);
	C(tail);
	C(end);

	atomic_inc(&(skb_shinfo(skb)->dataref));
	skb->cloned = 1;

	return n;
}


void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
{
	unsigned int csum;
	long csstart;

	if (skb->ip_summed == CHECKSUM_HW)
		csstart = skb->h.raw - skb->data;
	else
		csstart = skb_headlen(skb);

	if (csstart > skb_headlen(skb))
		BUG();

	memcpy(to, skb->data, csstart);

	csum = 0;
	if (csstart != skb->len)
		csum = skb_copy_and_csum_bits(skb, csstart, to + csstart,
					      skb->len - csstart, 0);

	if (skb->ip_summed == CHECKSUM_HW) {
		long csstuff = csstart + skb->csum;

		*((unsigned short *)(to + csstuff)) = csum_fold(csum);
	}
}


unsigned int skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
				    u8 *to, int len, unsigned int csum)
{
	int start = skb_headlen(skb);
	int i, copy = start - offset;
	int pos = 0;

	/* Copy header. */
	if (copy > 0) {
		if (copy > len)
			copy = len;
		csum = csum_partial_copy_nocheck(skb->data + offset, to,
						 copy, csum);
		if ((len -= copy) == 0)
			return csum;
		offset += copy;
		to     += copy;
		pos	= copy;
	}

	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
		int end;

		BUG_TRAP(start <= offset + len);

		end = start + skb_shinfo(skb)->frags[i].size;
		if ((copy = end - offset) > 0) {
			unsigned int csum2;
			u8 *vaddr;
			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];

			if (copy > len)
				copy = len;
			vaddr = kmap_skb_frag(frag);
			csum2 = csum_partial_copy_nocheck(vaddr +
							  frag->page_offset +
							  offset - start, to,
							  copy, 0);
			kunmap_skb_frag(vaddr);
			csum = csum_block_add(csum, csum2, pos);
			if (!(len -= copy))
				return csum;
			offset += copy;
			to     += copy;
			pos    += copy;
		}
		start = end;
	}

	if (skb_shinfo(skb)->frag_list) {
		struct sk_buff *list = skb_shinfo(skb)->frag_list;

		for (; list; list = list->next) {
			unsigned int csum2;
			int end;

			BUG_TRAP(start <= offset + len);

			end = start + list->len;
			if ((copy = end - offset) > 0) {
				if (copy > len)
					copy = len;
				csum2 = skb_copy_and_csum_bits(list,
							       offset - start,
							       to, copy, 0);
				csum = csum_block_add(csum, csum2, pos);
				if ((len -= copy) == 0)
					return csum;
				offset += copy;
				to     += copy;
				pos    += copy;
			}
			start = end;
		}
	}
	if (len)
		BUG();
	return csum;
}


unsigned int skb_checksum(const struct sk_buff *skb, int offset,
			  int len, unsigned int csum)
{
	int start = skb_headlen(skb);
	int i, copy = start - offset;
	int pos = 0;

	/* Checksum header. */
	if (copy > 0) {
		if (copy > len)
			copy = len;
		csum = csum_partial(skb->data + offset, copy, csum);
		if ((len -= copy) == 0)
			return csum;
		offset += copy;
		pos	= copy;
	}

	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
		int end;

		BUG_TRAP(start <= offset + len);

		end = start + skb_shinfo(skb)->frags[i].size;
		if ((copy = end - offset) > 0) {
			unsigned int csum2;
			u8 *vaddr;
			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];

			if (copy > len)
				copy = len;
			vaddr = kmap_skb_frag(frag);
			csum2 = csum_partial(vaddr + frag->page_offset +
					     offset - start, copy, 0);
			kunmap_skb_frag(vaddr);
			csum = csum_block_add(csum, csum2, pos);
			if (!(len -= copy))
				return csum;
			offset += copy;
			pos    += copy;
		}
		start = end;
	}

	if (skb_shinfo(skb)->frag_list) {
		struct sk_buff *list = skb_shinfo(skb)->frag_list;

		for (; list; list = list->next) {
			int end;

			BUG_TRAP(start <= offset + len);

			end = start + list->len;
			if ((copy = end - offset) > 0) {
				unsigned int csum2;
				if (copy > len)
					copy = len;
				csum2 = skb_checksum(list, offset - start,
						     copy, 0);
				csum = csum_block_add(csum, csum2, pos);
				if ((len -= copy) == 0)
					return csum;
				offset += copy;
				pos    += copy;
			}
			start = end;
		}
	}
	if (len)
		BUG();

	return csum;
}


static int __init dev_proc_init(void)
{
	int rc = -ENOMEM;

	if (!proc_net_fops_create("dev", S_IRUGO, &dev_seq_fops))
		goto out;
	if (!proc_net_fops_create("softnet_stat", S_IRUGO, &softnet_seq_fops))
		goto out_dev;
	if (wireless_proc_init())
		goto out_softnet;
	rc = 0;
out:
	return rc;
out_softnet:
	proc_net_remove("softnet_stat");
out_dev:
	proc_net_remove("dev");
	goto out;
}


int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, struct net_device *dev,
	       struct in6_addr *saddr, struct in6_addr *daddr,
	       int proto, int len)
{
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct ipv6hdr *hdr;
	int totlen;

	skb->protocol = htons(ETH_P_IPV6);
	skb->dev = dev;

	totlen = len + sizeof(struct ipv6hdr);

	hdr = (struct ipv6hdr *) skb_put(skb, sizeof(struct ipv6hdr));
	skb->nh.ipv6h = hdr;

	*(u32*)hdr = htonl(0x60000000);

	hdr->payload_len = htons(len);
	hdr->nexthdr = proto;
	hdr->hop_limit = np->hop_limit;

	ipv6_addr_copy(&hdr->saddr, saddr);
	ipv6_addr_copy(&hdr->daddr, daddr);

	return 0;
}


static int udp_reuseport_add_sock(struct sock *sk, struct udp_hslot *hslot)
{
	struct net *net = sock_net(sk);
	kuid_t uid = sock_i_uid(sk);
	struct sock *sk2;

	sk_for_each(sk2, &hslot->head) {
		if (net_eq(sock_net(sk2), net) &&
		    sk2 != sk &&
		    sk2->sk_family == sk->sk_family &&
		    ipv6_only_sock(sk2) == ipv6_only_sock(sk) &&
		    (udp_sk(sk2)->udp_port_hash == udp_sk(sk)->udp_port_hash) &&
		    (sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
		    sk2->sk_reuseport && uid_eq(uid, sock_i_uid(sk2)) &&
		    inet_rcv_saddr_equal(sk, sk2, false)) {
			return reuseport_add_sock(sk, sk2);
		}
	}

	/* Initial allocation may have already happened via setsockopt */
	if (!rcu_access_pointer(sk->sk_reuseport_cb))
		return reuseport_alloc(sk);
	return 0;
}


static int ip_setup_cork(struct sock *sk, struct inet_cork *cork,
			 struct ipcm_cookie *ipc, struct rtable **rtp)
{
	struct ip_options_rcu *opt;
	struct rtable *rt;

	/*
	 * setup for corking.
	 */
	opt = ipc->opt;
	if (opt) {
		if (!cork->opt) {
			cork->opt = kmalloc(sizeof(struct ip_options) + 40,
					    sk->sk_allocation);
			if (unlikely(!cork->opt))
				return -ENOBUFS;
		}
		memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen);
		cork->flags |= IPCORK_OPT;
		cork->addr = ipc->addr;
	}
	rt = *rtp;
	if (unlikely(!rt))
		return -EFAULT;
	/*
	 * We steal reference to this route, caller should not release it
	 */
	*rtp = NULL;
	cork->fragsize = ip_sk_use_pmtu(sk) ?
			 dst_mtu(&rt->dst) : rt->dst.dev->mtu;
	cork->dst = &rt->dst;
	cork->length = 0;
	cork->ttl = ipc->ttl;
	cork->tos = ipc->tos;
	cork->priority = ipc->priority;
	cork->tx_flags = ipc->tx_flags;

	return 0;
}


void udp_v4_early_demux(struct sk_buff *skb)
{
	struct net *net = dev_net(skb->dev);
	const struct iphdr *iph;
	const struct udphdr *uh;
	struct sock *sk = NULL;
	struct dst_entry *dst;
	int dif = skb->dev->ifindex;
	int ours;

	/* validate the packet */
	if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr)))
		return;

	iph = ip_hdr(skb);
	uh = udp_hdr(skb);

	if (skb->pkt_type == PACKET_BROADCAST ||
	    skb->pkt_type == PACKET_MULTICAST) {
		struct in_device *in_dev = __in_dev_get_rcu(skb->dev);

		if (!in_dev)
			return;

		/* we are supposed to accept bcast packets */
		if (skb->pkt_type == PACKET_MULTICAST) {
			ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr,
					       iph->protocol);
			if (!ours)
				return;
		}

		sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr,
						   uh->source, iph->saddr, dif);
	} else if (skb->pkt_type == PACKET_HOST) {
		sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr,
					     uh->source, iph->saddr, dif);
	}

	if (!sk || !refcount_inc_not_zero(&sk->sk_refcnt))
		return;

	skb->sk = sk;
	skb->destructor = sock_efree;
	dst = READ_ONCE(sk->sk_rx_dst);

	if (dst)
		dst = dst_check(dst, 0);
	if (dst) {
		/* set noref for now.
		 * any place which wants to hold dst has to call
		 * dst_hold_safe()
		 */
		skb_dst_set_noref(skb, dst);
	}
}


static bool udp_skb_has_head_state(struct sk_buff *skb)
{
	return !(udp_skb_scratch(skb)->_tsize_state & UDP_SKB_IS_STATELESS);
}


static int udp_lib_lport_inuse2(struct net *net, __u16 num,
				struct udp_hslot *hslot2,
				struct sock *sk)
{
	struct sock *sk2;
	kuid_t uid = sock_i_uid(sk);
	int res = 0;

	spin_lock(&hslot2->lock);
	udp_portaddr_for_each_entry(sk2, &hslot2->head) {
		if (net_eq(sock_net(sk2), net) &&
		    sk2 != sk &&
		    (udp_sk(sk2)->udp_port_hash == num) &&
		    (!sk2->sk_reuse || !sk->sk_reuse) &&
		    (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if ||
		     sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
		    inet_rcv_saddr_equal(sk, sk2, true)) {
			if (sk2->sk_reuseport && sk->sk_reuseport &&
			    !rcu_access_pointer(sk->sk_reuseport_cb) &&
			    uid_eq(uid, sock_i_uid(sk2))) {
				res = 0;
			} else {
				res = 1;
			}
			break;
		}
	}
	spin_unlock(&hslot2->lock);
	return res;
}


static int ip_mc_finish_output(struct net *net, struct sock *sk,
			       struct sk_buff *skb)
{
	int ret;

	ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb);
	if (ret) {
		kfree_skb(skb);
		return ret;
	}

	return dev_loopback_xmit(net, sk, skb);
}


static int do_timerfd_gettime(int ufd, struct itimerspec *t)
{
	struct fd f;
	struct timerfd_ctx *ctx;
	int ret = timerfd_fget(ufd, &f);
	if (ret)
		return ret;
	ctx = f.file->private_data;

	spin_lock_irq(&ctx->wqh.lock);
	if (ctx->expired && ctx->tintv) {
		ctx->expired = 0;

		if (isalarm(ctx)) {
			ctx->ticks +=
				alarm_forward_now(
					&ctx->t.alarm, ctx->tintv) - 1;
			alarm_restart(&ctx->t.alarm);
		} else {
			ctx->ticks +=
				hrtimer_forward_now(&ctx->t.tmr, ctx->tintv)
				- 1;
			hrtimer_restart(&ctx->t.tmr);
		}
	}
	t->it_value = ktime_to_timespec(timerfd_get_remaining(ctx));
	t->it_interval = ktime_to_timespec(ctx->tintv);
	spin_unlock_irq(&ctx->wqh.lock);
	fdput(f);
	return 0;
}


int f2fs_inode_dirtied(struct inode *inode, bool sync)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
	int ret = 0;

	spin_lock(&sbi->inode_lock[DIRTY_META]);
	if (is_inode_flag_set(inode, FI_DIRTY_INODE)) {
		ret = 1;
	} else {
		set_inode_flag(inode, FI_DIRTY_INODE);
		stat_inc_dirty_inode(sbi, DIRTY_META);
	}
	if (sync && list_empty(&F2FS_I(inode)->gdirty_list)) {
		list_add_tail(&F2FS_I(inode)->gdirty_list,
				&sbi->inode_list[DIRTY_META]);
		inc_page_count(sbi, F2FS_DIRTY_IMETA);
	}
	spin_unlock(&sbi->inode_lock[DIRTY_META]);
	return ret;
}


void f2fs_inode_synced(struct inode *inode)
{
	struct f2fs_sb_info *sbi = F2FS_I_SB(inode);

	spin_lock(&sbi->inode_lock[DIRTY_META]);
	if (!is_inode_flag_set(inode, FI_DIRTY_INODE)) {
		spin_unlock(&sbi->inode_lock[DIRTY_META]);
		return;
	}
	if (!list_empty(&F2FS_I(inode)->gdirty_list)) {
		list_del_init(&F2FS_I(inode)->gdirty_list);
		dec_page_count(sbi, F2FS_DIRTY_IMETA);
	}
	clear_inode_flag(inode, FI_DIRTY_INODE);
	clear_inode_flag(inode, FI_AUTO_RECOVER);
	stat_dec_dirty_inode(F2FS_I_SB(inode), DIRTY_META);
	spin_unlock(&sbi->inode_lock[DIRTY_META]);
}


static ssize_t f2fs_attr_store(struct kobject *kobj, struct attribute *attr,
						const char *buf, size_t len)
{
	struct f2fs_sb_info *sbi = container_of(kobj, struct f2fs_sb_info,
									s_kobj);
	struct f2fs_attr *a = container_of(attr, struct f2fs_attr, attr);

	return a->store ? a->store(a, sbi, buf, len) : 0;
}


static void f2fs_build_fault_attr(struct f2fs_sb_info *sbi,
						unsigned int rate)
{
	struct f2fs_fault_info *ffi = &sbi->fault_info;

	if (rate) {
		atomic_set(&ffi->inject_ops, 0);
		ffi->inject_rate = rate;
		ffi->inject_type = (1 << FAULT_MAX) - 1;
	} else {
		memset(ffi, 0, sizeof(struct f2fs_fault_info));
	}
}


static int segment_info_seq_show(struct seq_file *seq, void *offset)
{
	struct super_block *sb = seq->private;
	struct f2fs_sb_info *sbi = F2FS_SB(sb);
	unsigned int total_segs =
			le32_to_cpu(sbi->raw_super->segment_count_main);
	int i;

	seq_puts(seq, "format: segment_type|valid_blocks\n"
		"segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");

	for (i = 0; i < total_segs; i++) {
		struct seg_entry *se = get_seg_entry(sbi, i);

		if ((i % 10) == 0)
			seq_printf(seq, "%-10d", i);
		seq_printf(seq, "%d|%-3u", se->type,
					get_valid_blocks(sbi, i, false));
		if ((i % 10) == 9 || i == (total_segs - 1))
			seq_putc(seq, '\n');
		else
			seq_putc(seq, ' ');
	}

	return 0;
}


static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
{
	struct f2fs_sb_info *sbi = F2FS_SB(root->d_sb);

	if (!f2fs_readonly(sbi->sb) && test_opt(sbi, BG_GC)) {
		if (test_opt(sbi, FORCE_FG_GC))
			seq_printf(seq, ",background_gc=%s", "sync");
		else
			seq_printf(seq, ",background_gc=%s", "on");
	} else {
		seq_printf(seq, ",background_gc=%s", "off");
	}
	if (test_opt(sbi, DISABLE_ROLL_FORWARD))
		seq_puts(seq, ",disable_roll_forward");
	if (test_opt(sbi, DISCARD))
		seq_puts(seq, ",discard");
	if (test_opt(sbi, NOHEAP))
		seq_puts(seq, ",no_heap");
	else
		seq_puts(seq, ",heap");
#ifdef CONFIG_F2FS_FS_XATTR
	if (test_opt(sbi, XATTR_USER))
		seq_puts(seq, ",user_xattr");
	else
		seq_puts(seq, ",nouser_xattr");
	if (test_opt(sbi, INLINE_XATTR))
		seq_puts(seq, ",inline_xattr");
	else
		seq_puts(seq, ",noinline_xattr");
#endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL
	if (test_opt(sbi, POSIX_ACL))
		seq_puts(seq, ",acl");
	else
		seq_puts(seq, ",noacl");
#endif
	if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
		seq_puts(seq, ",disable_ext_identify");
	if (test_opt(sbi, INLINE_DATA))
		seq_puts(seq, ",inline_data");
	else
		seq_puts(seq, ",noinline_data");
	if (test_opt(sbi, INLINE_DENTRY))
		seq_puts(seq, ",inline_dentry");
	else
		seq_puts(seq, ",noinline_dentry");
	if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))
		seq_puts(seq, ",flush_merge");
	if (test_opt(sbi, NOBARRIER))
		seq_puts(seq, ",nobarrier");
	if (test_opt(sbi, FASTBOOT))
		seq_puts(seq, ",fastboot");
	if (test_opt(sbi, EXTENT_CACHE))
		seq_puts(seq, ",extent_cache");
	else
		seq_puts(seq, ",noextent_cache");
	if (test_opt(sbi, DATA_FLUSH))
		seq_puts(seq, ",data_flush");

	seq_puts(seq, ",mode=");
	if (test_opt(sbi, ADAPTIVE))
		seq_puts(seq, "adaptive");
	else if (test_opt(sbi, LFS))
		seq_puts(seq, "lfs");
	seq_printf(seq, ",active_logs=%u", sbi->active_logs);
	if (F2FS_IO_SIZE_BITS(sbi))
		seq_printf(seq, ",io_size=%uKB", F2FS_IO_SIZE_KB(sbi));
#ifdef CONFIG_F2FS_FAULT_INJECTION
	if (test_opt(sbi, FAULT_INJECTION))
		seq_puts(seq, ",fault_injection");
#endif

	return 0;
}


static int parse_options(struct super_block *sb, char *options)
{
	struct f2fs_sb_info *sbi = F2FS_SB(sb);
	struct request_queue *q;
	substring_t args[MAX_OPT_ARGS];
	char *p, *name;
	int arg = 0;

	if (!options)
		return 0;

	while ((p = strsep(&options, ",")) != NULL) {
		int token;
		if (!*p)
			continue;
		/*
		 * Initialize args struct so we know whether arg was
		 * found; some options take optional arguments.
		 */
		args[0].to = args[0].from = NULL;
		token = match_token(p, f2fs_tokens, args);

		switch (token) {
		case Opt_gc_background:
			name = match_strdup(&args[0]);

			if (!name)
				return -ENOMEM;
			if (strlen(name) == 2 && !strncmp(name, "on", 2)) {
				set_opt(sbi, BG_GC);
				clear_opt(sbi, FORCE_FG_GC);
			} else if (strlen(name) == 3 && !strncmp(name, "off", 3)) {
				clear_opt(sbi, BG_GC);
				clear_opt(sbi, FORCE_FG_GC);
			} else if (strlen(name) == 4 && !strncmp(name, "sync", 4)) {
				set_opt(sbi, BG_GC);
				set_opt(sbi, FORCE_FG_GC);
			} else {
				kfree(name);
				return -EINVAL;
			}
			kfree(name);
			break;
		case Opt_disable_roll_forward:
			set_opt(sbi, DISABLE_ROLL_FORWARD);
			break;
		case Opt_norecovery:
			/* this option mounts f2fs with ro */
			set_opt(sbi, DISABLE_ROLL_FORWARD);
			if (!f2fs_readonly(sb))
				return -EINVAL;
			break;
		case Opt_discard:
			q = bdev_get_queue(sb->s_bdev);
			if (blk_queue_discard(q)) {
				set_opt(sbi, DISCARD);
			} else if (!f2fs_sb_mounted_blkzoned(sb)) {
				f2fs_msg(sb, KERN_WARNING,
					"mounting with \"discard\" option, but "
					"the device does not support discard");
			}
			break;
		case Opt_nodiscard:
			if (f2fs_sb_mounted_blkzoned(sb)) {
				f2fs_msg(sb, KERN_WARNING,
					"discard is required for zoned block devices");
				return -EINVAL;
			}
			clear_opt(sbi, DISCARD);
			break;
		case Opt_noheap:
			set_opt(sbi, NOHEAP);
			break;
		case Opt_heap:
			clear_opt(sbi, NOHEAP);
			break;
#ifdef CONFIG_F2FS_FS_XATTR
		case Opt_user_xattr:
			set_opt(sbi, XATTR_USER);
			break;
		case Opt_nouser_xattr:
			clear_opt(sbi, XATTR_USER);
			break;
		case Opt_inline_xattr:
			set_opt(sbi, INLINE_XATTR);
			break;
		case Opt_noinline_xattr:
			clear_opt(sbi, INLINE_XATTR);
			break;
#else
		case Opt_user_xattr:
			f2fs_msg(sb, KERN_INFO,
				"user_xattr options not supported");
			break;
		case Opt_nouser_xattr:
			f2fs_msg(sb, KERN_INFO,
				"nouser_xattr options not supported");
			break;
		case Opt_inline_xattr:
			f2fs_msg(sb, KERN_INFO,
				"inline_xattr options not supported");
			break;
		case Opt_noinline_xattr:
			f2fs_msg(sb, KERN_INFO,
				"noinline_xattr options not supported");
			break;
#endif
#ifdef CONFIG_F2FS_FS_POSIX_ACL
		case Opt_acl:
			set_opt(sbi, POSIX_ACL);
			break;
		case Opt_noacl:
			clear_opt(sbi, POSIX_ACL);
			break;
#else
		case Opt_acl:
			f2fs_msg(sb, KERN_INFO, "acl options not supported");
			break;
		case Opt_noacl:
			f2fs_msg(sb, KERN_INFO, "noacl options not supported");
			break;
#endif
		case Opt_active_logs:
			if (args->from && match_int(args, &arg))
				return -EINVAL;
			if (arg != 2 && arg != 4 && arg != NR_CURSEG_TYPE)
				return -EINVAL;
			sbi->active_logs = arg;
			break;
		case Opt_disable_ext_identify:
			set_opt(sbi, DISABLE_EXT_IDENTIFY);
			break;
		case Opt_inline_data:
			set_opt(sbi, INLINE_DATA);
			break;
		case Opt_inline_dentry:
			set_opt(sbi, INLINE_DENTRY);
			break;
		case Opt_noinline_dentry:
			clear_opt(sbi, INLINE_DENTRY);
			break;
		case Opt_flush_merge:
			set_opt(sbi, FLUSH_MERGE);
			break;
		case Opt_noflush_merge:
			clear_opt(sbi, FLUSH_MERGE);
			break;
		case Opt_nobarrier:
			set_opt(sbi, NOBARRIER);
			break;
		case Opt_fastboot:
			set_opt(sbi, FASTBOOT);
			break;
		case Opt_extent_cache:
			set_opt(sbi, EXTENT_CACHE);
			break;
		case Opt_noextent_cache:
			clear_opt(sbi, EXTENT_CACHE);
			break;
		case Opt_noinline_data:
			clear_opt(sbi, INLINE_DATA);
			break;
		case Opt_data_flush:
			set_opt(sbi, DATA_FLUSH);
			break;
		case Opt_mode:
			name = match_strdup(&args[0]);

			if (!name)
				return -ENOMEM;
			if (strlen(name) == 8 &&
					!strncmp(name, "adaptive", 8)) {
				if (f2fs_sb_mounted_blkzoned(sb)) {
					f2fs_msg(sb, KERN_WARNING,
						 "adaptive mode is not allowed with "
						 "zoned block device feature");
					kfree(name);
					return -EINVAL;
				}
				set_opt_mode(sbi, F2FS_MOUNT_ADAPTIVE);
			} else if (strlen(name) == 3 &&
					!strncmp(name, "lfs", 3)) {
				set_opt_mode(sbi, F2FS_MOUNT_LFS);
			} else {
				kfree(name);
				return -EINVAL;
			}
			kfree(name);
			break;
		case Opt_io_size_bits:
			if (args->from && match_int(args, &arg))
				return -EINVAL;
			if (arg > __ilog2_u32(BIO_MAX_PAGES)) {
				f2fs_msg(sb, KERN_WARNING,
					"Not support %d, larger than %d",
					1 << arg, BIO_MAX_PAGES);
				return -EINVAL;
			}
			sbi->write_io_size_bits = arg;
			break;
		case Opt_fault_injection:
			if (args->from && match_int(args, &arg))
				return -EINVAL;
#ifdef CONFIG_F2FS_FAULT_INJECTION
			f2fs_build_fault_attr(sbi, arg);
			set_opt(sbi, FAULT_INJECTION);
#else
			f2fs_msg(sb, KERN_INFO,
				"FAULT_INJECTION was not selected");
#endif
			break;
		case Opt_lazytime:
			sb->s_flags |= MS_LAZYTIME;
			break;
		case Opt_nolazytime:
			sb->s_flags &= ~MS_LAZYTIME;
			break;
		default:
			f2fs_msg(sb, KERN_ERR,
				"Unrecognized mount option \"%s\" or missing value",
				p);
			return -EINVAL;
		}
	}

	if (F2FS_IO_SIZE_BITS(sbi) && !test_opt(sbi, LFS)) {
		f2fs_msg(sb, KERN_ERR,
				"Should set mode=lfs with %uKB-sized IO",
				F2FS_IO_SIZE_KB(sbi));
		return -EINVAL;
	}
	return 0;
}


static inline bool sanity_check_area_boundary(struct f2fs_sb_info *sbi,
					struct buffer_head *bh)
{
	struct f2fs_super_block *raw_super = (struct f2fs_super_block *)
					(bh->b_data + F2FS_SUPER_OFFSET);
	struct super_block *sb = sbi->sb;
	u32 segment0_blkaddr = le32_to_cpu(raw_super->segment0_blkaddr);
	u32 cp_blkaddr = le32_to_cpu(raw_super->cp_blkaddr);
	u32 sit_blkaddr = le32_to_cpu(raw_super->sit_blkaddr);
	u32 nat_blkaddr = le32_to_cpu(raw_super->nat_blkaddr);
	u32 ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
	u32 main_blkaddr = le32_to_cpu(raw_super->main_blkaddr);
	u32 segment_count_ckpt = le32_to_cpu(raw_super->segment_count_ckpt);
	u32 segment_count_sit = le32_to_cpu(raw_super->segment_count_sit);
	u32 segment_count_nat = le32_to_cpu(raw_super->segment_count_nat);
	u32 segment_count_ssa = le32_to_cpu(raw_super->segment_count_ssa);
	u32 segment_count_main = le32_to_cpu(raw_super->segment_count_main);
	u32 segment_count = le32_to_cpu(raw_super->segment_count);
	u32 log_blocks_per_seg = le32_to_cpu(raw_super->log_blocks_per_seg);
	u64 main_end_blkaddr = main_blkaddr +
				(segment_count_main << log_blocks_per_seg);
	u64 seg_end_blkaddr = segment0_blkaddr +
				(segment_count << log_blocks_per_seg);

	if (segment0_blkaddr != cp_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Mismatch start address, segment0(%u) cp_blkaddr(%u)",
			segment0_blkaddr, cp_blkaddr);
		return true;
	}

	if (cp_blkaddr + (segment_count_ckpt << log_blocks_per_seg) !=
							sit_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Wrong CP boundary, start(%u) end(%u) blocks(%u)",
			cp_blkaddr, sit_blkaddr,
			segment_count_ckpt << log_blocks_per_seg);
		return true;
	}

	if (sit_blkaddr + (segment_count_sit << log_blocks_per_seg) !=
							nat_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Wrong SIT boundary, start(%u) end(%u) blocks(%u)",
			sit_blkaddr, nat_blkaddr,
			segment_count_sit << log_blocks_per_seg);
		return true;
	}

	if (nat_blkaddr + (segment_count_nat << log_blocks_per_seg) !=
							ssa_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Wrong NAT boundary, start(%u) end(%u) blocks(%u)",
			nat_blkaddr, ssa_blkaddr,
			segment_count_nat << log_blocks_per_seg);
		return true;
	}

	if (ssa_blkaddr + (segment_count_ssa << log_blocks_per_seg) !=
							main_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Wrong SSA boundary, start(%u) end(%u) blocks(%u)",
			ssa_blkaddr, main_blkaddr,
			segment_count_ssa << log_blocks_per_seg);
		return true;
	}

	if (main_end_blkaddr > seg_end_blkaddr) {
		f2fs_msg(sb, KERN_INFO,
			"Wrong MAIN_AREA boundary, start(%u) end(%u) block(%u)",
			main_blkaddr,
			segment0_blkaddr +
				(segment_count << log_blocks_per_seg),
			segment_count_main << log_blocks_per_seg);
		return true;
	} else if (main_end_blkaddr < seg_end_blkaddr) {
		int err = 0;
		char *res;

		/* fix in-memory information all the time */
		raw_super->segment_count = cpu_to_le32((main_end_blkaddr -
				segment0_blkaddr) >> log_blocks_per_seg);

		if (f2fs_readonly(sb) || bdev_read_only(sb->s_bdev)) {
			set_sbi_flag(sbi, SBI_NEED_SB_WRITE);
			res = "internally";
		} else {
			err = __f2fs_commit_super(bh, NULL);
			res = err ? "failed" : "done";
		}
		f2fs_msg(sb, KERN_INFO,
			"Fix alignment : %s, start(%u) end(%u) block(%u)",
			res, main_blkaddr,
			segment0_blkaddr +
				(segment_count << log_blocks_per_seg),
			segment_count_main << log_blocks_per_seg);
		if (err)
			return true;
	}
	return false;
}


static int __f2fs_commit_super(struct buffer_head *bh,
			struct f2fs_super_block *super)
{
	lock_buffer(bh);
	if (super)
		memcpy(bh->b_data + F2FS_SUPER_OFFSET, super, sizeof(*super));
	set_buffer_uptodate(bh);
	set_buffer_dirty(bh);
	unlock_buffer(bh);

	/* it's rare case, we can do fua all the time */
	return __sync_dirty_buffer(bh, REQ_PREFLUSH | REQ_FUA);
}


isdn_capi_rec_hl_msg(capi_msg *cm)
{
	switch (cm->Command) {
	case CAPI_FACILITY:
		/* in the moment only handled in tty */
		return (isdn_tty_capi_facility(cm));
	default:
		return (-1);
	}
}


isdn_command(isdn_ctrl *cmd)
{
	if (cmd->driver == -1) {
		printk(KERN_WARNING "isdn_command command(%x) driver -1\n", cmd->command);
		return (1);
	}
	if (!dev->drv[cmd->driver]) {
		printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d] NULL\n",
		       cmd->command, cmd->driver);
		return (1);
	}
	if (!dev->drv[cmd->driver]->interface) {
		printk(KERN_WARNING "isdn_command command(%x) dev->drv[%d]->interface NULL\n",
		       cmd->command, cmd->driver);
		return (1);
	}
	if (cmd->command == ISDN_CMD_SETL2) {
		int idx = isdn_dc2minor(cmd->driver, cmd->arg & 255);
		unsigned long l2prot = (cmd->arg >> 8) & 255;
		unsigned long features = (dev->drv[cmd->driver]->interface->features
					  >> ISDN_FEATURE_L2_SHIFT) &
			ISDN_FEATURE_L2_MASK;
		unsigned long l2_feature = (1 << l2prot);

		switch (l2prot) {
		case ISDN_PROTO_L2_V11096:
		case ISDN_PROTO_L2_V11019:
		case ISDN_PROTO_L2_V11038:
			/* If V.110 requested, but not supported by
			 * HL-driver, set emulator-flag and change
			 * Layer-2 to transparent
			 */
			if (!(features & l2_feature)) {
				dev->v110emu[idx] = l2prot;
				cmd->arg = (cmd->arg & 255) |
					(ISDN_PROTO_L2_TRANS << 8);
			} else
				dev->v110emu[idx] = 0;
		}
	}
	return dev->drv[cmd->driver]->interface->command(cmd);
}


void isdn_net_writebuf_skb(isdn_net_local *lp, struct sk_buff *skb)
{
	int ret;
	int len = skb->len;     /* save len */

	/* before obtaining the lock the caller should have checked that
	   the lp isn't busy */
	if (isdn_net_lp_busy(lp)) {
		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
		goto error;
	}

	if (!(lp->flags & ISDN_NET_CONNECTED)) {
		printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__);
		goto error;
	}
	ret = isdn_writebuf_skb_stub(lp->isdn_device, lp->isdn_channel, 1, skb);
	if (ret != len) {
		/* we should never get here */
		printk(KERN_WARNING "%s: HL driver queue full\n", lp->netdev->dev->name);
		goto error;
	}

	lp->transcount += len;
	isdn_net_inc_frame_cnt(lp);
	return;

error:
	dev_kfree_skb(skb);
	lp->stats.tx_errors++;

}


isdn_net_dial_req(isdn_net_local *lp)
{
	/* is there a better error code? */
	if (!(ISDN_NET_DIALMODE(*lp) == ISDN_NET_DM_AUTO)) return -EBUSY;

	return isdn_net_force_dial_lp(lp);
}


isdn_timer_ctrl(int tf, int onoff)
{
	unsigned long flags;
	int old_tflags;

	spin_lock_irqsave(&dev->timerlock, flags);
	if ((tf & ISDN_TIMER_SLOW) && (!(dev->tflags & ISDN_TIMER_SLOW))) {
		/* If the slow-timer wasn't activated until now */
		isdn_timer_cnt1 = 0;
		isdn_timer_cnt2 = 0;
	}
	old_tflags = dev->tflags;
	if (onoff)
		dev->tflags |= tf;
	else
		dev->tflags &= ~tf;
	if (dev->tflags && !old_tflags)
		mod_timer(&dev->timer, jiffies + ISDN_TIMER_RES);
	spin_unlock_irqrestore(&dev->timerlock, flags);
}


isdn_close(struct inode *ino, struct file *filep)
{
	uint minor = iminor(ino);

	mutex_lock(&isdn_mutex);
	if (minor == ISDN_MINOR_STATUS) {
		infostruct *p = dev->infochain;
		infostruct *q = NULL;

		while (p) {
			if (p->private == (char *) &(filep->private_data)) {
				if (q)
					q->next = p->next;
				else
					dev->infochain = (infostruct *) (p->next);
				kfree(p);
				goto out;
			}
			q = p;
			p = (infostruct *) (p->next);
		}
		printk(KERN_WARNING "isdn: No private data while closing isdnctrl\n");
		goto out;
	}
	isdn_unlock_drivers();
	if (minor <= ISDN_MINOR_BMAX)
		goto out;
	if (minor <= ISDN_MINOR_CTRLMAX) {
		if (dev->profd == current)
			dev->profd = NULL;
		goto out;
	}
#ifdef CONFIG_ISDN_PPP
	if (minor <= ISDN_MINOR_PPPMAX)
		isdn_ppp_release(minor - ISDN_MINOR_PPP, filep);
#endif

out:
	mutex_unlock(&isdn_mutex);
	return 0;
}


isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
{
	unsigned short hl = dev->drv[lp->isdn_device]->interface->hl_hdrlen;
	struct sk_buff *skb;

	skb = alloc_skb(hl + len, GFP_ATOMIC);
	if (skb)
		skb_reserve(skb, hl);
	else
		printk("isdn out of mem at %s:%d!\n", __FILE__, __LINE__);
	return skb;
}


static void __exit isdn_exit(void)
{
#ifdef CONFIG_ISDN_PPP
	isdn_ppp_cleanup();
#endif
	if (isdn_net_rmall() < 0) {
		printk(KERN_WARNING "isdn: net-device busy, remove cancelled\n");
		return;
	}
	isdn_tty_exit();
	unregister_chrdev(ISDN_MAJOR, "isdn");
	del_timer_sync(&dev->timer);
	/* call vfree with interrupts enabled, else it will hang */
	vfree(dev);
	printk(KERN_NOTICE "ISDN-subsystem unloaded\n");
}


static int isdn_net_ioctl(struct net_device *dev,
			  struct ifreq *ifr, int cmd)
{
	isdn_net_local *lp = netdev_priv(dev);

	switch (lp->p_encap) {
#ifdef CONFIG_ISDN_PPP
	case ISDN_NET_ENCAP_SYNCPPP:
		return isdn_ppp_dev_ioctl(dev, ifr, cmd);
#endif
	case ISDN_NET_ENCAP_CISCOHDLCK:
		return isdn_ciscohdlck_dev_ioctl(dev, ifr, cmd);
	default:
		return -EINVAL;
	}
}


static void isdn_net_tx_timeout(struct net_device *ndev)
{
	isdn_net_local *lp = netdev_priv(ndev);

	printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate);
	if (!lp->dialstate) {
		lp->stats.tx_errors++;
		/*
		 * There is a certain probability that this currently
		 * works at all because if we always wake up the interface,
		 * then upper layer will try to send the next packet
		 * immediately. And then, the old clean_up logic in the
		 * driver will hopefully continue to work as it used to do.
		 *
		 * This is rather primitive right know, we better should
		 * clean internal queues here, in particular for multilink and
		 * ppp, and reset HL driver's channel, too.   --HE
		 *
		 * actually, this may not matter at all, because ISDN hardware
		 * should not see transmitter hangs at all IMO
		 * changed KERN_DEBUG to KERN_WARNING to find out if this is
		 * ever called   --KG
		 */
	}
	netif_trans_update(ndev);
	netif_wake_queue(ndev);
}


isdn_net_unreachable(struct net_device *dev, struct sk_buff *skb, char *reason)
{
	if (skb) {

		u_short proto = ntohs(skb->protocol);

		printk(KERN_DEBUG "isdn_net: %s: %s, signalling dst_link_failure %s\n",
		       dev->name,
		       (reason != NULL) ? reason : "unknown",
		       (proto != ETH_P_IP) ? "Protocol != ETH_P_IP" : "");

		dst_link_failure(skb);
	}
	else {  /* dial not triggered by rawIP packet */
		printk(KERN_DEBUG "isdn_net: %s: %s\n",
		       dev->name,
		       (reason != NULL) ? reason : "reason unknown");
	}
}


isdn_write(struct file *file, const char __user *buf, size_t count, loff_t *off)
{
	uint minor = iminor(file_inode(file));
	int drvidx;
	int chidx;
	int retval;

	if (minor == ISDN_MINOR_STATUS)
		return -EPERM;
	if (!dev->drivers)
		return -ENODEV;

	mutex_lock(&isdn_mutex);
	if (minor <= ISDN_MINOR_BMAX) {
		printk(KERN_WARNING "isdn_write minor %d obsolete!\n", minor);
		drvidx = isdn_minor2drv(minor);
		if (drvidx < 0) {
			retval = -ENODEV;
			goto out;
		}
		if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING)) {
			retval = -ENODEV;
			goto out;
		}
		chidx = isdn_minor2chan(minor);
		wait_event_interruptible(dev->drv[drvidx]->snd_waitq[chidx],
			(retval = isdn_writebuf_stub(drvidx, chidx, buf, count)));
		goto out;
	}
	if (minor <= ISDN_MINOR_CTRLMAX) {
		drvidx = isdn_minor2drv(minor - ISDN_MINOR_CTRL);
		if (drvidx < 0) {
			retval = -ENODEV;
			goto out;
		}
		/*
		 * We want to use the isdnctrl device to load the firmware
		 *
		 if (!(dev->drv[drvidx]->flags & DRV_FLAG_RUNNING))
		 return -ENODEV;
		*/
		if (dev->drv[drvidx]->interface->writecmd)
			retval = dev->drv[drvidx]->interface->
				writecmd(buf, count, drvidx,
					 isdn_minor2chan(minor - ISDN_MINOR_CTRL));
		else
			retval = count;
		goto out;
	}
#ifdef CONFIG_ISDN_PPP
	if (minor <= ISDN_MINOR_PPPMAX) {
		retval = isdn_ppp_write(minor - ISDN_MINOR_PPP, file, buf, count);
		goto out;
	}
#endif
	retval = -ENODEV;
out:
	mutex_unlock(&isdn_mutex);
	return retval;
}


isdn_net_autohup(void)
{
	isdn_net_dev *p = dev->netdev;
	int anymore;

	anymore = 0;
	while (p) {
		isdn_net_local *l = p->local;
		if (jiffies == last_jiffies)
			l->cps = l->transcount;
		else
			l->cps = (l->transcount * HZ) / (jiffies - last_jiffies);
		l->transcount = 0;
		if (dev->net_verbose > 3)
			printk(KERN_DEBUG "%s: %d bogocps\n", p->dev->name, l->cps);
		if ((l->flags & ISDN_NET_CONNECTED) && (!l->dialstate)) {
			anymore = 1;
			l->huptimer++;
			/*
			 * if there is some dialmode where timeout-hangup
			 * should _not_ be done, check for that here
			 */
			if ((l->onhtime) &&
			    (l->huptimer > l->onhtime))
			{
				if (l->hupflags & ISDN_MANCHARGE &&
				    l->hupflags & ISDN_CHARGEHUP) {
					while (time_after(jiffies, l->chargetime + l->chargeint))
						l->chargetime += l->chargeint;
					if (time_after(jiffies, l->chargetime + l->chargeint - 2 * HZ))
						if (l->outgoing || l->hupflags & ISDN_INHUP)
							isdn_net_hangup(p->dev);
				} else if (l->outgoing) {
					if (l->hupflags & ISDN_CHARGEHUP) {
						if (l->hupflags & ISDN_WAITCHARGE) {
							printk(KERN_DEBUG "isdn_net: Hupflags of %s are %X\n",
							       p->dev->name, l->hupflags);
							isdn_net_hangup(p->dev);
						} else if (time_after(jiffies, l->chargetime + l->chargeint)) {
							printk(KERN_DEBUG
							       "isdn_net: %s: chtime = %lu, chint = %d\n",
							       p->dev->name, l->chargetime, l->chargeint);
							isdn_net_hangup(p->dev);
						}
					} else
						isdn_net_hangup(p->dev);
				} else if (l->hupflags & ISDN_INHUP)
					isdn_net_hangup(p->dev);
			}

			if (dev->global_flags & ISDN_GLOBAL_STOPPED || (ISDN_NET_DIALMODE(*l) == ISDN_NET_DM_OFF)) {
				isdn_net_hangup(p->dev);
				break;
			}
		}
		p = (isdn_net_dev *) p->next;
	}
	last_jiffies = jiffies;
	isdn_timer_ctrl(ISDN_TIMER_NETHANGUP, anymore);
}


static int ipa_blob_seek(void* wand,long position)
{
  return (int)SeekBlob((Image*)wand,(MagickOffsetType) position,SEEK_SET);
}


static void ipa_device_end(wmfAPI * API)
{
  wmf_magick_t
    *ddata = WMF_MAGICK_GetData(API);

  /* Reset any existing clip paths by popping wand */
  if (ddata->clipping)
    (void) PopDrawingWand(WmfDrawingWand);
  ddata->clipping = MagickFalse;

  /* Make SVG output happy */
  (void) PopDrawingWand(WmfDrawingWand);
}


static void draw_pattern_push( wmfAPI* API,
                               unsigned long id,
                               unsigned long columns,
                               unsigned long rows )
{
  char
    pattern_id[MagickPathExtent];

  (void) FormatLocaleString(pattern_id,MagickPathExtent,"brush_%lu",id);
  (void) DrawPushPattern(WmfDrawingWand,pattern_id,0,0,columns,rows);
}


static void draw_stroke_color_rgb( wmfAPI* API, const wmfRGB* rgb )
{
  PixelWand
    *stroke_color;

  stroke_color=NewPixelWand();
  PixelSetRedQuantum(stroke_color,ScaleCharToQuantum(rgb->r));
  PixelSetGreenQuantum(stroke_color,ScaleCharToQuantum(rgb->g));
  PixelSetBlueQuantum(stroke_color,ScaleCharToQuantum(rgb->b));
  PixelSetAlphaQuantum(stroke_color,OpaqueAlpha);
  DrawSetStrokeColor(WmfDrawingWand,stroke_color);
  stroke_color=DestroyPixelWand(stroke_color);
}


static void util_set_pen(wmfAPI * API, wmfDC * dc)
{
  wmf_magick_t
    *ddata = WMF_MAGICK_GetData(API);

  wmfPen
    *pen = 0;

  double
    pen_width,
    pixel_width;

  unsigned int
    pen_style;

  pen = WMF_DC_PEN(dc);

  pen_width = (WMF_PEN_WIDTH(pen) + WMF_PEN_HEIGHT(pen)) / 2;

  /* Pixel width is inverse of pixel scale */
  pixel_width = (((double) 1 / (ddata->scale_x)) +
                 ((double) 1 / (ddata->scale_y))) / 2;

  /* Don't allow pen_width to be much less than pixel_width in order
     to avoid dissapearing or spider-web lines */
  pen_width = MagickMax(pen_width, pixel_width*0.8);

  pen_style = (unsigned int) WMF_PEN_STYLE(pen);

  /* Pen style specified? */
  if (pen_style == PS_NULL)
    {
      draw_stroke_color_string(WmfDrawingWand,"none");
      return;
    }

  DrawSetStrokeAntialias(WmfDrawingWand, MagickTrue );
  DrawSetStrokeWidth(WmfDrawingWand, (unsigned long) MagickMax(0.0, pen_width));

  {
    LineCap
      linecap;

    switch ((unsigned int) WMF_PEN_ENDCAP(pen))
      {
      case PS_ENDCAP_SQUARE:
        linecap = SquareCap;
        break;
      case PS_ENDCAP_ROUND:
        linecap = RoundCap;
        break;
      case PS_ENDCAP_FLAT:
      default:
        linecap = ButtCap;
        break;
      }
    DrawSetStrokeLineCap(WmfDrawingWand, linecap);
  }

  {
    LineJoin
      linejoin;

    switch ((unsigned int) WMF_PEN_JOIN(pen))
      {
      case PS_JOIN_BEVEL:
        linejoin = BevelJoin;
        break;
      case PS_JOIN_ROUND:
        linejoin = RoundJoin;
        break;
      case PS_JOIN_MITER:
      default:
        linejoin = MiterJoin;
        break;
      }
    DrawSetStrokeLineJoin(WmfDrawingWand,linejoin);
  }

  {
    double
      dasharray[7];

    switch (pen_style)
      {
      case PS_DASH:    /* -------  */
        {
          /* Pattern 18,7 */
          dasharray[0] = pixel_width * 18;
          dasharray[1] = pixel_width * 7;
          dasharray[2] = 0;

          DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
          (void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
          break;
        }
      case PS_ALTERNATE:
      case PS_DOT:    /* .......  */
        {
          /* Pattern 3,3 */
          dasharray[0] = pixel_width * 3;
          dasharray[1] = pixel_width * 3;
          dasharray[2] = 0;

          DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
          (void) DrawSetStrokeDashArray(WmfDrawingWand,2,dasharray);
          break;
        }
      case PS_DASHDOT:    /* _._._._  */
        {
          /* Pattern 9,6,3,6 */
          dasharray[0] = pixel_width * 9;
          dasharray[1] = pixel_width * 6;
          dasharray[2] = pixel_width * 3;
          dasharray[3] = pixel_width * 6;
          dasharray[4] = 0;

          DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
          (void) DrawSetStrokeDashArray(WmfDrawingWand,4,dasharray);
          break;
        }
      case PS_DASHDOTDOT:  /* _.._.._  */
        {
          /* Pattern 9,3,3,3,3,3 */
          dasharray[0] = pixel_width * 9;
          dasharray[1] = pixel_width * 3;
          dasharray[2] = pixel_width * 3;
          dasharray[3] = pixel_width * 3;
          dasharray[4] = pixel_width * 3;
          dasharray[5] = pixel_width * 3;
          dasharray[6] = 0;

          DrawSetStrokeAntialias(WmfDrawingWand,MagickFalse);
          (void) DrawSetStrokeDashArray(WmfDrawingWand,6,dasharray);
          break;
        }
      case PS_INSIDEFRAME:  /* There is nothing to do in this case... */
      case PS_SOLID:
      default:
        {
          (void) DrawSetStrokeDashArray(WmfDrawingWand,0,(double *) NULL);
          break;
        }
      }
  }

  draw_stroke_color_rgb(API,WMF_PEN_COLOR(pen));
}


static int MSLHasExternalSubset(void *context)
{
  MSLInfo
    *msl_info;

  /*
    Does this document has an external subset?
  */
  (void) LogMagickEvent(CoderEvent,GetMagickModule(),
    "  SAX.MSLHasExternalSubset()");
  msl_info=(MSLInfo *) context;
  return(msl_info->document->extSubset != NULL);
}


ModuleExport void UnregisterMSLImage(void)
{
  (void) UnregisterMagickInfo("MSL");
#if defined(MAGICKCORE_XML_DELEGATE)
  xmlCleanupParser();
#endif
}


static inline Image *GetImageCache(const ImageInfo *image_info,const char *path,
  ExceptionInfo *exception)
{
  char
    key[MagickPathExtent];

  ExceptionInfo
    *sans_exception;

  Image
    *image;

  ImageInfo
    *read_info;

  (void) FormatLocaleString(key,MagickPathExtent,"cache:%s",path);
  sans_exception=AcquireExceptionInfo();
  image=(Image *) GetImageRegistry(ImageRegistryType,key,sans_exception);
  sans_exception=DestroyExceptionInfo(sans_exception);
  if (image != (Image *) NULL)
    return(image);
  read_info=CloneImageInfo(image_info);
  (void) CopyMagickString(read_info->filename,path,MagickPathExtent);
  image=ReadImage(read_info,exception);
  read_info=DestroyImageInfo(read_info);
  if (image != (Image *) NULL)
    (void) SetImageRegistry(ImageRegistryType,key,image,exception);
  return(image);
}


static MagickBooleanType IsDCX(const unsigned char *magick,const size_t length)
{
  if (length < 4)
    return(MagickFalse);
  if (memcmp(magick,"\261\150\336\72",4) == 0)
    return(MagickTrue);
  return(MagickFalse);
}


static gboolean tcp_server_event(GIOChannel *channel, GIOCondition condition,
							gpointer user_data)
{
	int sk;
	struct server_data *server = user_data;

	sk = g_io_channel_unix_get_fd(channel);
	if (sk == 0)
		return FALSE;

	if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
		GSList *list;
hangup:
		debug("TCP server channel closed, sk %d", sk);

		/*
		 * Discard any partial response which is buffered; better
		 * to get a proper response from a working server.
		 */
		g_free(server->incoming_reply);
		server->incoming_reply = NULL;

		list = request_list;
		while (list) {
			struct request_data *req = list->data;
			struct domain_hdr *hdr;
			list = list->next;

			if (req->protocol == IPPROTO_UDP)
				continue;

			if (!req->request)
				continue;

			/*
			 * If we're not waiting for any further response
			 * from another name server, then we send an error
			 * response to the client.
			 */
			if (req->numserv && --(req->numserv))
				continue;

			hdr = (void *) (req->request + 2);
			hdr->id = req->srcid;
			send_response(req->client_sk, req->request,
				req->request_len, NULL, 0, IPPROTO_TCP);

			request_list = g_slist_remove(request_list, req);
		}

		destroy_server(server);

		return FALSE;
	}

	if ((condition & G_IO_OUT) && !server->connected) {
		GSList *list;
		GList *domains;
		bool no_request_sent = true;
		struct server_data *udp_server;

		udp_server = find_server(server->index, server->server,
								IPPROTO_UDP);
		if (udp_server) {
			for (domains = udp_server->domains; domains;
						domains = domains->next) {
				char *dom = domains->data;

				debug("Adding domain %s to %s",
						dom, server->server);

				server->domains = g_list_append(server->domains,
								g_strdup(dom));
			}
		}

		server->connected = true;
		server_list = g_slist_append(server_list, server);

		if (server->timeout > 0) {
			g_source_remove(server->timeout);
			server->timeout = 0;
		}

		for (list = request_list; list; ) {
			struct request_data *req = list->data;
			int status;

			if (req->protocol == IPPROTO_UDP) {
				list = list->next;
				continue;
			}

			debug("Sending req %s over TCP", (char *)req->name);

			status = ns_resolv(server, req,
						req->request, req->name);
			if (status > 0) {
				/*
				 * A cached result was sent,
				 * so the request can be released
				 */
				list = list->next;
				request_list = g_slist_remove(request_list, req);
				destroy_request_data(req);
				continue;
			}

			if (status < 0) {
				list = list->next;
				continue;
			}

			no_request_sent = false;

			if (req->timeout > 0)
				g_source_remove(req->timeout);

			req->timeout = g_timeout_add_seconds(30,
						request_timeout, req);
			list = list->next;
		}

		if (no_request_sent) {
			destroy_server(server);
			return FALSE;
		}

	} else if (condition & G_IO_IN) {
		struct partial_reply *reply = server->incoming_reply;
		int bytes_recv;

		if (!reply) {
			unsigned char reply_len_buf[2];
			uint16_t reply_len;

			bytes_recv = recv(sk, reply_len_buf, 2, MSG_PEEK);
			if (!bytes_recv) {
				goto hangup;
			} else if (bytes_recv < 0) {
				if (errno == EAGAIN || errno == EWOULDBLOCK)
					return TRUE;

				connman_error("DNS proxy error %s",
						strerror(errno));
				goto hangup;
			} else if (bytes_recv < 2)
				return TRUE;

			reply_len = reply_len_buf[1] | reply_len_buf[0] << 8;
			reply_len += 2;

			debug("TCP reply %d bytes from %d", reply_len, sk);

			reply = g_try_malloc(sizeof(*reply) + reply_len + 2);
			if (!reply)
				return TRUE;

			reply->len = reply_len;
			reply->received = 0;

			server->incoming_reply = reply;
		}

		while (reply->received < reply->len) {
			bytes_recv = recv(sk, reply->buf + reply->received,
					reply->len - reply->received, 0);
			if (!bytes_recv) {
				connman_error("DNS proxy TCP disconnect");
				break;
			} else if (bytes_recv < 0) {
				if (errno == EAGAIN || errno == EWOULDBLOCK)
					return TRUE;

				connman_error("DNS proxy error %s",
						strerror(errno));
				break;
			}
			reply->received += bytes_recv;
		}

		forward_dns_reply(reply->buf, reply->received, IPPROTO_TCP,
					server);

		g_free(reply);
		server->incoming_reply = NULL;

		destroy_server(server);

		return FALSE;
	}

	return TRUE;
}


static void cache_refresh_iterator(gpointer key, gpointer value,
					gpointer user_data)
{
	struct cache_entry *entry = value;

	cache_refresh_entry(entry);
}


void __connman_dnsproxy_cleanup(void)
{
	DBG("");

	if (cache_timer) {
		g_source_remove(cache_timer);
		cache_timer = 0;
	}

	if (cache) {
		g_hash_table_destroy(cache);
		cache = NULL;
	}

	connman_notifier_unregister(&dnsproxy_notifier);

	g_hash_table_foreach(listener_table, remove_listener, NULL);

	g_hash_table_destroy(listener_table);

	g_hash_table_destroy(partial_tcp_req_table);
}


int __connman_dnsproxy_remove(int index, const char *domain,
							const char *server)
{
	DBG("index %d server %s", index, server);

	if (!server && !domain)
		return -EINVAL;

	if (!server) {
		remove_domain(index, domain);

		return 0;
	}

	if (g_str_equal(server, "127.0.0.1"))
		return -ENODEV;

	if (g_str_equal(server, "::1"))
		return -ENODEV;

	remove_server(index, domain, server, IPPROTO_UDP);
	remove_server(index, domain, server, IPPROTO_TCP);

	return 0;
}


static void destroy_request_data(struct request_data *req)
{
	if (req->timeout > 0)
		g_source_remove(req->timeout);

	g_free(req->resp);
	g_free(req->request);
	g_free(req->name);
	g_free(req);
}


static gboolean udp6_listener_event(GIOChannel *channel, GIOCondition condition,
				gpointer user_data)
{
	struct listener_data *ifdata = user_data;

	return udp_listener_event(channel, condition, user_data, AF_INET6,
				&ifdata->udp6_listener_watch);
}


ia64_patch_imm60 (u64 insn_addr, u64 val)
{
	/* The assembler may generate offset pointing to either slot 1
	   or slot 2 for a long (2-slot) instruction, occupying slots 1
	   and 2.  */
  	insn_addr &= -16UL;
	ia64_patch(insn_addr + 2,
		   0x011ffffe000UL, (  ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
				     | ((val & 0x00000000000fffffUL) << 13) /* bit  0 -> 13 */));
	ia64_patch(insn_addr + 1, 0x1fffffffffcUL, val >> 18);
}