1 package com.android.server.wifi.anqp; 2 3 import java.net.ProtocolException; 4 import java.nio.ByteBuffer; 5 import java.nio.charset.StandardCharsets; 6 import java.util.Collections; 7 import java.util.HashMap; 8 import java.util.Locale; 9 import java.util.Map; 10 11 /** 12 * The Civic Location ANQP Element, IEEE802.11-2012 section 8.4.4.13 13 */ 14 public class CivicLocationElement extends ANQPElement { 15 public enum LocationType {DHCPServer, NwkElement, Client} 16 17 private static final int GEOCONF_CIVIC4 = 99; 18 private static final int RFC4776 = 0; // Table 8-77, 1=vendor specific 19 20 private final LocationType mLocationType; 21 private final Locale mLocale; 22 private final Map<CAType, String> mValues; 23 24 public CivicLocationElement(Constants.ANQPElementType infoID, ByteBuffer payload) 25 throws ProtocolException { 26 super(infoID); 27 28 if (payload.remaining() < 6) { 29 throw new ProtocolException("Runt civic location:" + payload.remaining()); 30 } 31 32 int locType = payload.get() & Constants.BYTE_MASK; 33 if (locType != RFC4776) { 34 throw new ProtocolException("Bad Civic location type: " + locType); 35 } 36 37 int locSubType = payload.get() & Constants.BYTE_MASK; 38 if (locSubType != GEOCONF_CIVIC4) { 39 throw new ProtocolException("Unexpected Civic location sub-type: " + locSubType + 40 " (cannot handle sub elements)"); 41 } 42 43 int length = payload.get() & Constants.BYTE_MASK; 44 if (length > payload.remaining()) { 45 throw new ProtocolException("Invalid CA type length: " + length); 46 } 47 48 int what = payload.get() & Constants.BYTE_MASK; 49 mLocationType = what < LocationType.values().length ? LocationType.values()[what] : null; 50 51 mLocale = Locale.forLanguageTag(Constants.getString(payload, 2, StandardCharsets.US_ASCII)); 52 53 mValues = new HashMap<CAType, String>(); 54 while (payload.hasRemaining()) { 55 int caTypeNumber = payload.get() & Constants.BYTE_MASK; 56 CAType caType = s_caTypes.get(caTypeNumber); 57 58 int caValLen = payload.get() & Constants.BYTE_MASK; 59 if (caValLen > payload.remaining()) { 60 throw new ProtocolException("Bad CA value length: " + caValLen); 61 } 62 byte[] caValOctets = new byte[caValLen]; 63 payload.get(caValOctets); 64 65 if (caType != null) { 66 mValues.put(caType, new String(caValOctets, StandardCharsets.UTF_8)); 67 } 68 } 69 } 70 71 public LocationType getLocationType() { 72 return mLocationType; 73 } 74 75 public Locale getLocale() { 76 return mLocale; 77 } 78 79 public Map<CAType, String> getValues() { 80 return Collections.unmodifiableMap(mValues); 81 } 82 83 @Override 84 public String toString() { 85 return "CivicLocation{" + 86 "mLocationType=" + mLocationType + 87 ", mLocale=" + mLocale + 88 ", mValues=" + mValues + 89 '}'; 90 } 91 92 private static final Map<Integer, CAType> s_caTypes = new HashMap<Integer, CAType>(); 93 94 public static final int LANGUAGE = 0; 95 public static final int STATE_PROVINCE = 1; 96 public static final int COUNTY_DISTRICT = 2; 97 public static final int CITY = 3; 98 public static final int DIVISION_BOROUGH = 4; 99 public static final int BLOCK = 5; 100 public static final int STREET_GROUP = 6; 101 public static final int STREET_DIRECTION = 16; 102 public static final int LEADING_STREET_SUFFIX = 17; 103 public static final int STREET_SUFFIX = 18; 104 public static final int HOUSE_NUMBER = 19; 105 public static final int HOUSE_NUMBER_SUFFIX = 20; 106 public static final int LANDMARK = 21; 107 public static final int ADDITIONAL_LOCATION = 22; 108 public static final int NAME = 23; 109 public static final int POSTAL_ZIP = 24; 110 public static final int BUILDING = 25; 111 public static final int UNIT = 26; 112 public static final int FLOOR = 27; 113 public static final int ROOM = 28; 114 public static final int TYPE = 29; 115 public static final int POSTAL_COMMUNITY = 30; 116 public static final int PO_BOX = 31; 117 public static final int ADDITIONAL_CODE = 32; 118 public static final int SEAT_DESK = 33; 119 public static final int PRIMARY_ROAD = 34; 120 public static final int ROAD_SECTION = 35; 121 public static final int BRANCH_ROAD = 36; 122 public static final int SUB_BRANCH_ROAD = 37; 123 public static final int STREET_NAME_PRE_MOD = 38; 124 public static final int STREET_NAME_POST_MOD = 39; 125 public static final int SCRIPT = 128; 126 public static final int RESERVED = 255; 127 128 public enum CAType { 129 Language, 130 StateProvince, 131 CountyDistrict, 132 City, 133 DivisionBorough, 134 Block, 135 StreetGroup, 136 StreetDirection, 137 LeadingStreetSuffix, 138 StreetSuffix, 139 HouseNumber, 140 HouseNumberSuffix, 141 Landmark, 142 AdditionalLocation, 143 Name, 144 PostalZIP, 145 Building, 146 Unit, 147 Floor, 148 Room, 149 Type, 150 PostalCommunity, 151 POBox, 152 AdditionalCode, 153 SeatDesk, 154 PrimaryRoad, 155 RoadSection, 156 BranchRoad, 157 SubBranchRoad, 158 StreetNamePreMod, 159 StreetNamePostMod, 160 Script, 161 Reserved 162 } 163 164 static { 165 s_caTypes.put(LANGUAGE, CAType.Language); 166 s_caTypes.put(STATE_PROVINCE, CAType.StateProvince); 167 s_caTypes.put(COUNTY_DISTRICT, CAType.CountyDistrict); 168 s_caTypes.put(CITY, CAType.City); 169 s_caTypes.put(DIVISION_BOROUGH, CAType.DivisionBorough); 170 s_caTypes.put(BLOCK, CAType.Block); 171 s_caTypes.put(STREET_GROUP, CAType.StreetGroup); 172 s_caTypes.put(STREET_DIRECTION, CAType.StreetDirection); 173 s_caTypes.put(LEADING_STREET_SUFFIX, CAType.LeadingStreetSuffix); 174 s_caTypes.put(STREET_SUFFIX, CAType.StreetSuffix); 175 s_caTypes.put(HOUSE_NUMBER, CAType.HouseNumber); 176 s_caTypes.put(HOUSE_NUMBER_SUFFIX, CAType.HouseNumberSuffix); 177 s_caTypes.put(LANDMARK, CAType.Landmark); 178 s_caTypes.put(ADDITIONAL_LOCATION, CAType.AdditionalLocation); 179 s_caTypes.put(NAME, CAType.Name); 180 s_caTypes.put(POSTAL_ZIP, CAType.PostalZIP); 181 s_caTypes.put(BUILDING, CAType.Building); 182 s_caTypes.put(UNIT, CAType.Unit); 183 s_caTypes.put(FLOOR, CAType.Floor); 184 s_caTypes.put(ROOM, CAType.Room); 185 s_caTypes.put(TYPE, CAType.Type); 186 s_caTypes.put(POSTAL_COMMUNITY, CAType.PostalCommunity); 187 s_caTypes.put(PO_BOX, CAType.POBox); 188 s_caTypes.put(ADDITIONAL_CODE, CAType.AdditionalCode); 189 s_caTypes.put(SEAT_DESK, CAType.SeatDesk); 190 s_caTypes.put(PRIMARY_ROAD, CAType.PrimaryRoad); 191 s_caTypes.put(ROAD_SECTION, CAType.RoadSection); 192 s_caTypes.put(BRANCH_ROAD, CAType.BranchRoad); 193 s_caTypes.put(SUB_BRANCH_ROAD, CAType.SubBranchRoad); 194 s_caTypes.put(STREET_NAME_PRE_MOD, CAType.StreetNamePreMod); 195 s_caTypes.put(STREET_NAME_POST_MOD, CAType.StreetNamePostMod); 196 s_caTypes.put(SCRIPT, CAType.Script); 197 s_caTypes.put(RESERVED, CAType.Reserved); 198 } 199 } 200