# File radius/packet.rb, line 106
    def unpack(data)
      p_hdr = "CCna16a*"
      rcodes = {
	1 => 'Access-Request',
	2  => 'Access-Accept',
	3  => 'Access-Reject',
	4  => 'Accounting-Request',
	5  => 'Accounting-Response',
	11 => 'Access-Challenge',
	12 => 'Status-Server',
	13 => 'Status-Client'
      }

      @code, @identifier, len, @authenticator, attrdat = data.unpack(p_hdr)
      @code = rcodes[@code]

      unset_all

      while (attrdat.length > 0)
	length = attrdat.unpack("xC")[0].to_i
	tval, value = attrdat.unpack("Cxa#{length-2}")

	tval = tval.to_i
	if (tval == VSA_TYPE)
	  # handle vendor-specific attributes
	  vid, vtype, vlength = value.unpack("NCC")
	  # XXX - How do we calculate the length of the VSA?  It's not
	  # defined!

	  # XXX - 3COM seems to do things a bit differently.  The 'if'
	  # below takes care of that.  This is based on the
	  # Net::Radius code.
	  if vid == 429
	    # 3COM packet
	    vid, vtype = value.unpack("NN")
	    vvalue = value.unpack("xxxxxxxxa#{length - 10}")[0]
	  else
	    vvalue = value.unpack("xxxxxxa#{vlength - 2}")[0]
	  end
	  type = @dict.vsattr_numtype(vid, vtype)
	  if type == nil
	    raise "Garbled vendor-specific attribute #{vid}/#{vtype}"
	  end
	  val = case type
		when 'string' then vvalue
		when 'integer'
		  (@dict.vsaval_has_name(vid, vtype)) ?
		  @dict.vsaval_name(vid, vtype, vvalue.unpack("N")[0]) :
		    vvalue.unpack("N")[0]
		when 'ipaddr' then inet_ntoa(vvalue)
		when 'time' then vvalue.unpack("N")[0]
		when 'date' then vvalue.unpack("N")[0]
		else
		  raise "Unknown VSattribute type found: #{vtype}"
		end
	  set_vsattr(vid, @dict.vsattr_name(vid, vtype), val)
	else
	  type = @dict.attr_numtype(tval)
	  raise "Garbled attribute #{tval}" if (type == nil)
	  val = case type
		when 'string' then value
		when 'integer'
		  @dict.val_has_name(tval) ? 
		  @dict.val_name(tval, value.unpack("N")[0]) :
		    value.unpack("N")[0]
		when 'ipaddr' then inet_ntoa(value.unpack("N")[0])
		when 'time' then value.unpack("N")[0]
		when 'date' then value.unpack("N")[0]
		else raise "Unknown attribute type found: #{type}"
		end
	  set_attr(@dict.attr_name(tval), val)
	end
	attrdat[0, length] = ""
      end
    end