1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * PPPoE common utilities and data. 24 * 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <errno.h> 33 #include <netdb.h> 34 #include <assert.h> 35 #include <stropts.h> 36 #include <sys/types.h> 37 #include <inet/common.h> 38 #include <netinet/in.h> 39 #include <net/sppptun.h> 40 #include <net/pppoe.h> 41 #include <arpa/inet.h> 42 43 #include "common.h" 44 45 /* Not all functions are used by all applications. Let lint know this. */ 46 /*LINTLIBRARY*/ 47 48 /* Common I/O buffers */ 49 uint32_t pkt_input[PKT_INPUT_LEN / sizeof (uint32_t)]; 50 uint32_t pkt_octl[PKT_OCTL_LEN / sizeof (uint32_t)]; 51 uint32_t pkt_output[PKT_OUTPUT_LEN / sizeof (uint32_t)]; 52 53 const char tunnam[] = "/dev/" PPP_TUN_NAME; 54 55 const ether_addr_t ether_bcast = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 56 57 /* 58 * Wrapper for standard strerror() function -- the standard allows 59 * that routine to return NULL, and that's inconvenient to handle. 60 * This function never returns NULL. 61 */ 62 const char * 63 mystrerror(int err) 64 { 65 const char *estr; 66 static char ebuf[64]; 67 68 if ((estr = strerror(err)) != NULL) 69 return (estr); 70 (void) snprintf(ebuf, sizeof (ebuf), "Error:%d", err); 71 return (ebuf); 72 } 73 74 /* 75 * Wrapper for standard perror() function -- the standard definition 76 * of perror doesn't include the program name in the output and is 77 * thus inconvenient to use. 78 */ 79 void 80 myperror(const char *emsg) 81 { 82 (void) fprintf(stderr, "%s: %s: %s\n", myname, emsg, 83 mystrerror(errno)); 84 } 85 86 /* 87 * Wrapper for standard getmsg() function. Completely discards any 88 * fragmented messages because we don't expect ever to see these from 89 * a properly functioning tunnel driver. Returns flags 90 * (MORECTL|MOREDATA) as seen by interface. 91 */ 92 int 93 mygetmsg(int fd, struct strbuf *ctrl, struct strbuf *data, int *flags) 94 { 95 int retv; 96 int hadflags; 97 98 hadflags = getmsg(fd, ctrl, data, flags); 99 if (hadflags <= 0 || !(hadflags & (MORECTL | MOREDATA))) 100 return (hadflags); 101 102 do { 103 if (flags != NULL) 104 *flags = 0; 105 retv = getmsg(fd, ctrl, data, flags); 106 } while (retv > 0 || (retv < 0 && errno == EINTR)); 107 108 /* 109 * What remains at this point is the tail end of the 110 * truncated message. Toss it. 111 */ 112 113 return (retv < 0 ? retv : hadflags); 114 } 115 116 /* 117 * Common wrapper function for STREAMS I_STR ioctl. Returns -1 on 118 * failure, 0 for success. 119 */ 120 int 121 strioctl(int fd, int cmd, void *ptr, int ilen, int olen) 122 { 123 struct strioctl str; 124 125 str.ic_cmd = cmd; 126 str.ic_timout = 0; /* Default timeout; 15 seconds */ 127 str.ic_len = ilen; 128 str.ic_dp = ptr; 129 130 if (ioctl(fd, I_STR, &str) == -1) { 131 return (-1); 132 } 133 if (str.ic_len != olen) { 134 errno = EINVAL; 135 return (-1); 136 } 137 return (0); 138 } 139 140 /* 141 * Format a PPPoE header in the user's buffer. The returned pointer 142 * is either identical to the first argument, or is NULL if it's not 143 * usable. On entry, dptr should point to the first byte after the 144 * Ethertype field, codeval should be one of the POECODE_* values, and 145 * sessionid should be the assigned session ID number or one of the 146 * special POESESS_* values. 147 */ 148 poep_t * 149 poe_mkheader(void *dptr, uint8_t codeval, int sessionid) 150 { 151 poep_t *poep; 152 153 /* Discard obvious junk. */ 154 assert(dptr != NULL && IS_P2ALIGNED(dptr, sizeof (poep_t *))); 155 156 /* Initialize the header */ 157 poep = (poep_t *)dptr; 158 poep->poep_version_type = POE_VERSION; 159 poep->poep_code = codeval; 160 poep->poep_session_id = htons(sessionid); 161 poep->poep_length = htons(0); 162 return (poep); 163 } 164 165 /* 166 * Validate that a given tag is intact. This is intended to be used 167 * in tag-parsing loops before attempting to access the tag data. 168 */ 169 boolean_t 170 poe_tagcheck(const poep_t *poep, int length, const uint8_t *tptr) 171 { 172 int plen; 173 const uint8_t *tstart, *tend; 174 175 if (poep == NULL || !IS_P2ALIGNED(poep, sizeof (uint16_t)) || 176 tptr == NULL || length < sizeof (*poep)) 177 return (B_FALSE); 178 179 plen = poe_length(poep); 180 if (plen + sizeof (*poep) > length) 181 return (B_FALSE); 182 183 tstart = (const uint8_t *)(poep+1); 184 tend = tstart + plen; 185 186 /* 187 * Note careful dereference of tptr; it might be near the end 188 * already, so we have to range check it before dereferencing 189 * to get the actual tag length. Yes, it looks like we have 190 * duplicate array end checks. No, they're not duplicates. 191 */ 192 if (tptr < tstart || tptr+POET_HDRLEN > tend || 193 tptr+POET_HDRLEN+POET_GET_LENG(tptr) > tend) 194 return (B_FALSE); 195 return (B_TRUE); 196 } 197 198 static int 199 poe_tag_insert(poep_t *poep, uint16_t ttype, const void *data, size_t dlen) 200 { 201 int plen; 202 uint8_t *dp; 203 204 plen = poe_length(poep); 205 if (data == NULL) 206 dlen = 0; 207 if (sizeof (*poep) + plen + POET_HDRLEN + dlen > PPPOE_MSGMAX) 208 return (-1); 209 dp = (uint8_t *)(poep + 1) + plen; 210 POET_SET_TYPE(dp, ttype); 211 POET_SET_LENG(dp, dlen); 212 if (dlen > 0) 213 (void) memcpy(POET_DATA(dp), data, dlen); 214 poep->poep_length = htons(plen + POET_HDRLEN + dlen); 215 return (0); 216 } 217 218 /* 219 * Add a tag with text string data to a PPPoE packet being 220 * constructed. Returns -1 if it doesn't fit, or 0 for success. 221 */ 222 int 223 poe_add_str(poep_t *poep, uint16_t ttype, const char *str) 224 { 225 return (poe_tag_insert(poep, ttype, str, strlen(str))); 226 } 227 228 /* 229 * Add a tag with 32-bit integer data to a PPPoE packet being 230 * constructed. Returns -1 if it doesn't fit, or 0 for success. 231 */ 232 int 233 poe_add_long(poep_t *poep, uint16_t ttype, uint32_t val) 234 { 235 val = htonl(val); 236 return (poe_tag_insert(poep, ttype, &val, sizeof (val))); 237 } 238 239 /* 240 * Add a tag with two 32-bit integers to a PPPoE packet being 241 * constructed. Returns -1 if it doesn't fit, or 0 for success. 242 */ 243 int 244 poe_two_longs(poep_t *poep, uint16_t ttype, uint32_t val1, uint32_t val2) 245 { 246 uint32_t vals[2]; 247 248 vals[0] = htonl(val1); 249 vals[1] = htonl(val2); 250 return (poe_tag_insert(poep, ttype, vals, sizeof (vals))); 251 } 252 253 /* 254 * Copy a single tag and its data from one PPPoE packet to a PPPoE 255 * packet being constructed. Returns -1 if it doesn't fit, or 0 for 256 * success. 257 */ 258 int 259 poe_tag_copy(poep_t *poep, const uint8_t *tagp) 260 { 261 int tlen; 262 int plen; 263 264 tlen = POET_GET_LENG(tagp) + POET_HDRLEN; 265 plen = poe_length(poep); 266 if (sizeof (*poep) + plen + tlen > PPPOE_MSGMAX) 267 return (-1); 268 (void) memcpy((uint8_t *)(poep + 1) + plen, tagp, tlen); 269 poep->poep_length = htons(tlen + plen); 270 return (0); 271 } 272 273 struct tag_list { 274 int tl_type; 275 const char *tl_name; 276 }; 277 278 /* List of PPPoE data tag types. */ 279 static const struct tag_list tag_list[] = { 280 { POETT_END, "End-Of-List" }, 281 { POETT_SERVICE, "Service-Name" }, 282 { POETT_ACCESS, "AC-Name" }, 283 { POETT_UNIQ, "Host-Uniq" }, 284 { POETT_COOKIE, "AC-Cookie" }, 285 { POETT_VENDOR, "Vendor-Specific" }, 286 { POETT_RELAY, "Relay-Session-Id" }, 287 { POETT_NAMERR, "Service-Name-Error" }, 288 { POETT_SYSERR, "AC-System-Error" }, 289 { POETT_GENERR, "Generic-Error" }, 290 { POETT_MULTI, "Multicast-Capable" }, 291 { POETT_HURL, "Host-URL" }, 292 { POETT_MOTM, "Message-Of-The-Minute" }, 293 { POETT_RTEADD, "IP-Route-Add" }, 294 { 0, NULL } 295 }; 296 297 /* List of PPPoE message code numbers. */ 298 static const struct tag_list code_list[] = { 299 { POECODE_DATA, "Data" }, 300 { POECODE_PADO, "Active Discovery Offer" }, 301 { POECODE_PADI, "Active Discovery Initiation" }, 302 { POECODE_PADR, "Active Discovery Request" }, 303 { POECODE_PADS, "Active Discovery Session-confirmation" }, 304 { POECODE_PADT, "Active Discovery Terminate" }, 305 { POECODE_PADM, "Active Discovery Message" }, 306 { POECODE_PADN, "Active Discovery Network" }, 307 { 0, NULL } 308 }; 309 310 /* 311 * Given a tag type number, return a pointer to a string describing 312 * the tag. 313 */ 314 const char * 315 poe_tagname(uint16_t tagtype) 316 { 317 const struct tag_list *tlp; 318 static char tname[32]; 319 320 for (tlp = tag_list; tlp->tl_name != NULL; tlp++) 321 if (tagtype == tlp->tl_type) 322 return (tlp->tl_name); 323 (void) sprintf(tname, "Tag%d", tagtype); 324 return (tname); 325 } 326 327 /* 328 * Given a PPPoE message code number, return a pointer to a string 329 * describing the message. 330 */ 331 const char * 332 poe_codename(uint8_t codetype) 333 { 334 const struct tag_list *tlp; 335 static char tname[32]; 336 337 for (tlp = code_list; tlp->tl_name != NULL; tlp++) 338 if (codetype == tlp->tl_type) 339 return (tlp->tl_name); 340 (void) sprintf(tname, "Code%d", codetype); 341 return (tname); 342 } 343 344 /* 345 * Given a tunnel driver address structure, return a pointer to a 346 * string naming that Ethernet host. 347 */ 348 const char * 349 ehost2(const struct ether_addr *ea) 350 { 351 static char hbuf[MAXHOSTNAMELEN+1]; 352 353 if (ea == NULL) 354 return ("NULL"); 355 if (ether_ntohost(hbuf, ea) == 0) 356 return (hbuf); 357 return (ether_ntoa(ea)); 358 } 359 360 const char * 361 ehost(const ppptun_atype *pap) 362 { 363 return (ehost2((const struct ether_addr *)pap)); 364 } 365 366 /* 367 * Given an Internet address (in network byte order), return a pointer 368 * to a string naming the host. 369 */ 370 const char * 371 ihost(uint32_t haddr) 372 { 373 struct hostent *hp; 374 struct sockaddr_in sin; 375 376 (void) memset(&sin, '\0', sizeof (sin)); 377 sin.sin_addr.s_addr = haddr; 378 hp = gethostbyaddr((const char *)&sin, sizeof (sin), AF_INET); 379 if (hp != NULL) 380 return (hp->h_name); 381 return (inet_ntoa(sin.sin_addr)); 382 } 383 384 int 385 hexdecode(char chr) 386 { 387 if (chr >= '0' && chr <= '9') 388 return ((int)(chr - '0')); 389 if (chr >= 'a' && chr <= 'f') 390 return ((int)(chr - 'a' + 10)); 391 return ((int)(chr - 'A' + 10)); 392 } 393