/* * bestmove * resign * win * <move1> [ponder <move2>] */ static int bestmove_parse(Usimsg *msg, const char *s) { const char *p; Token token; if ((p = token_get(&token, s)) == NULL) return -1; if (token_equal(&token, "resign")) return usimsg_pushnil(msg, USIOBJ_RESIGN); if (token_equal(&token, "win")) return usimsg_pushnil(msg, USIOBJ_WIN); if (usimsg_pushstr(msg, USIOBJ_MOVE, token.s, token.len) != 0) return -1; if ((p = token_get(&token, p)) == NULL) return 0; if (!token_equal(&token, "ponder")) return 0; if ((p = token_get(&token, p)) == NULL) return -1; if (usimsg_pushstr(msg, USIOBJ_MOVE, token.s, token.len) != 0) return -1; return 0; }
/* * id * name <program name> * author <program author> */ static int id_parse(Usimsg *msg, const char *s) { const char *p; Token token; if ((p = token_get(&token, s)) == NULL) return -1; if (token_equal(&token, "name")) return usimsg_pushstr(msg, USIOBJ_PROGNAME, p, strlen(p)); if (token_equal(&token, "author")) return usimsg_pushstr(msg, USIOBJ_AUTHOR, p, strlen(p)); return -1; }
/* * checkmate * notimplemented * timeout * nomate * <move1> ... <movei> */ static int checkmate_parse(Usimsg *msg, const char *s) { const char *p; Token token; if ((p = token_get(&token, s)) == NULL) return -1; if (token_equal(&token, "notimplemented")) return usimsg_pushnil(msg, USIOBJ_NOTIMPLEMENTED); if (token_equal(&token, "timeout")) return usimsg_pushnil(msg, USIOBJ_TIMEOUT); if (token_equal(&token, "nomate")) return usimsg_pushnil(msg, USIOBJ_NOMATE); return usimsg_pushstr(msg, USIOBJ_MOVE, token.s, strlen(token.s)); }
static Tbl * tbl_find(Tbl *root, Token *token) { Tbl *e; for (e = root; e->name != NULL; e++) if (token_equal(token, e->name)) return e; return NULL; }
boolean_t incoming_prefix_addrconf_process(struct phyint *pi, struct prefix *pr, uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback, boolean_t new_prefix) { struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; char abuf[INET6_ADDRSTRLEN]; char pbuf[INET6_ADDRSTRLEN]; uint32_t validtime, preftime; /* In seconds */ uint32_t recorded_validtime; /* In seconds */ int plen; struct prefix *other_pr; validtime = ntohl(po->nd_opt_pi_valid_time); preftime = ntohl(po->nd_opt_pi_preferred_time); plen = po->nd_opt_pi_prefix_len; if (!new_prefix) { /* * Check 2 hour rule on valid lifetime. * Follows: RFC 2462 * If we advertised this prefix ourselves we skip * these checks. They are also skipped if we did not * previously do addrconf on this prefix. */ recorded_validtime = pr->pr_ValidLifetime / MILLISEC; if (loopback || !(pr->pr_state & PR_AUTO) || validtime >= MIN_VALID_LIFETIME || /* LINTED - statement has no consequent */ validtime >= recorded_validtime) { /* OK */ } else if (recorded_validtime < MIN_VALID_LIFETIME && validtime < recorded_validtime) { /* Ignore the prefix */ (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, abuf, sizeof (abuf)); (void) inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix, pbuf, sizeof (pbuf)); logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " "too short valid lifetime %u stored %u " "- ignored\n", pbuf, plen, abuf, pi->pi_name, validtime, recorded_validtime); return (_B_TRUE); } else { /* * If the router clock runs slower than the * host by 1 second over 2 hours then this * test will set the lifetime back to 2 hours * once i.e. a lifetime decrementing in * realtime might cause the prefix to live an * extra 2 hours on the host. */ (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, abuf, sizeof (abuf)); (void) inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix, pbuf, sizeof (pbuf)); logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " "valid time %u stored %u rounded up " "to %u\n", pbuf, plen, abuf, pi->pi_name, validtime, recorded_validtime, MIN_VALID_LIFETIME); validtime = MIN_VALID_LIFETIME; } } /* * For RFC3041 addresses, need to take token lifetime * into account, too. */ if (pr->pr_flags & IFF_TEMPORARY) { uint_t cur_tpreftime = pi->pi_TmpPreferredLifetime - pi->pi_TmpDesyncFactor; if (new_prefix) { validtime = MIN(validtime, pi->pi_TmpValidLifetime); preftime = MIN(preftime, cur_tpreftime); } else { uint_t cur_vexp, cur_pexp, curtime; curtime = getcurrenttime() / MILLISEC; cur_vexp = pr->pr_CreateTime + pi->pi_TmpValidLifetime; cur_pexp = pr->pr_CreateTime + cur_tpreftime; if (curtime > cur_vexp) validtime = 0; else if ((curtime + validtime) > cur_vexp) validtime = cur_vexp - curtime; /* * If this is an existing address which was deprecated * because of a bad token, we don't want to update its * preferred lifetime! */ if ((pr->pr_PreferredLifetime == 0) && !token_equal(pr->pr_address, pi->pi_tmp_token, TMP_TOKEN_BITS)) preftime = 0; else if (curtime > cur_pexp) preftime = 0; else if ((curtime + preftime) > cur_pexp) preftime = cur_pexp - curtime; } if ((preftime != 0) && (preftime <= pi->pi_TmpRegenAdvance)) { (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, abuf, sizeof (abuf)); (void) inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix, pbuf, sizeof (pbuf)); logmsg(LOG_WARNING, "prefix opt %s/%u from %s on %s: " "preferred lifetime(%d) <= TmpRegenAdvance(%d)\n", pbuf, plen, abuf, pi->pi_name, preftime, pi->pi_TmpRegenAdvance); if (new_prefix) { prefix_update_ipadm_addrobj(pr, _B_FALSE); prefix_delete(pr); } return (_B_TRUE); } } if (debug & D_TMP) logmsg(LOG_DEBUG, "calculated lifetimes(%s, 0x%llx): v %d, " "p %d\n", pr->pr_name, pr->pr_flags, validtime, preftime); if (!(pr->pr_state & PR_AUTO)) { int i, tokenlen; in6_addr_t *token; /* * Form a new local address if the lengths match. */ if (pr->pr_flags & IFF_TEMPORARY) { if (IN6_IS_ADDR_UNSPECIFIED(&pi->pi_tmp_token)) { if (!tmptoken_create(pi)) { prefix_delete(pr); return (_B_TRUE); } } tokenlen = TMP_TOKEN_BITS; token = &pi->pi_tmp_token; } else { tokenlen = pi->pi_token_length; token = &pi->pi_token; } if (pr->pr_prefix_len + tokenlen != IPV6_ABITS) { (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, abuf, sizeof (abuf)); (void) inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix, pbuf, sizeof (pbuf)); logmsg(LOG_INFO, "prefix option %s/%u from %s on %s: " "mismatched length %d token length %d\n", pbuf, plen, abuf, pi->pi_name, pr->pr_prefix_len, tokenlen); return (_B_TRUE); } for (i = 0; i < 16; i++) { /* * prefix_create ensures that pr_prefix has all-zero * bits after prefixlen. */ pr->pr_address.s6_addr[i] = pr->pr_prefix.s6_addr[i] | token->s6_addr[i]; } /* * Check if any other physical interface has the same * address configured already */ if ((other_pr = prefix_lookup_addr_match(pr)) != NULL) { /* * Delete this prefix structure as kernel * does not allow duplicated addresses */ logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " "Duplicate prefix %s received on interface %s\n", inet_ntop(AF_INET6, &po->nd_opt_pi_prefix, abuf, sizeof (abuf)), pi->pi_name); logmsg(LOG_ERR, "incoming_prefix_addrconf_process: " "Prefix already exists in interface %s\n", other_pr->pr_physical->pi_name); if (new_prefix) { prefix_update_ipadm_addrobj(pr, _B_FALSE); prefix_delete(pr); return (_B_FALSE); } /* Ignore for addrconf purposes */ validtime = preftime = 0; } if ((pr->pr_flags & IFF_TEMPORARY) && new_prefix) { pr->pr_CreateTime = getcurrenttime() / MILLISEC; if (debug & D_TMP) logmsg(LOG_DEBUG, "created tmp addr(%s v %d p %d)\n", pr->pr_name, validtime, preftime); } } if (validtime != 0) pr->pr_state |= PR_AUTO; else pr->pr_state &= ~(PR_AUTO|PR_DEPRECATED); if (preftime != 0 || !(pr->pr_state & PR_AUTO)) pr->pr_state &= ~PR_DEPRECATED; else pr->pr_state |= PR_DEPRECATED; /* * Convert from seconds to milliseconds avoiding overflow. * If the lifetime in the packet is e.g. PREFIX_INFINITY - 1 * (4 billion seconds - about 130 years) we will in fact time * out the prefix after 4 billion milliseconds - 46 days). * Thus the longest lifetime (apart from infinity) is 46 days. * Note that this ensures that PREFIX_INFINITY still means "forever". */ if (validtime >= PREFIX_INFINITY / MILLISEC) pr->pr_ValidLifetime = PREFIX_INFINITY - 1; else pr->pr_ValidLifetime = validtime * MILLISEC; if (preftime >= PREFIX_INFINITY / MILLISEC) pr->pr_PreferredLifetime = PREFIX_INFINITY - 1; else pr->pr_PreferredLifetime = preftime * MILLISEC; pr->pr_AutonomousFlag = _B_TRUE; if (debug & D_PREFIX) { logmsg(LOG_DEBUG, "incoming_prefix_addrconf_process(%s, %s/%u) " "valid %u pref %u\n", pr->pr_physical->pi_name, inet_ntop(AF_INET6, (void *)&pr->pr_prefix, abuf, sizeof (abuf)), pr->pr_prefix_len, pr->pr_ValidLifetime, pr->pr_PreferredLifetime); } if (pr->pr_state & PR_AUTO) { /* Take the min of the two timeouts by calling it twice */ if (pr->pr_ValidLifetime != 0) timer_schedule(pr->pr_ValidLifetime); if (pr->pr_PreferredLifetime != 0) timer_schedule(pr->pr_PreferredLifetime); } if (pr->pr_kernel_state != pr->pr_state) { /* Log a message when an addrconf prefix goes away */ if ((pr->pr_kernel_state & PR_AUTO) && !(pr->pr_state & PR_AUTO)) { char abuf[INET6_ADDRSTRLEN]; logmsg(LOG_WARNING, "Address removed due to zero " "valid lifetime %s\n", inet_ntop(AF_INET6, (void *)&pr->pr_address, abuf, sizeof (abuf))); } prefix_update_k(pr); } return (_B_TRUE); }
/* * Process prefix options with the autonomous flag set. * Returns false if this prefix results in a bad address (duplicate) * This function needs to loop to find the same prefix multiple times * as if a failover happened earlier, the addresses belonging to * a different interface may be found here on this interface. */ static boolean_t incoming_prefix_addrconf(struct phyint *pi, uchar_t *opt, struct sockaddr_in6 *from, boolean_t loopback) { struct nd_opt_prefix_info *po = (struct nd_opt_prefix_info *)opt; int plen; struct prefix *pr; uint32_t validtime, preftime; /* In seconds */ char abuf[INET6_ADDRSTRLEN]; char pbuf[INET6_ADDRSTRLEN]; boolean_t found_pub = _B_FALSE; boolean_t found_tmp = _B_FALSE; boolean_t ret; validtime = ntohl(po->nd_opt_pi_valid_time); preftime = ntohl(po->nd_opt_pi_preferred_time); plen = po->nd_opt_pi_prefix_len; /* Sanity checks */ if (validtime < preftime) { (void) inet_ntop(AF_INET6, (void *)&from->sin6_addr, abuf, sizeof (abuf)); (void) inet_ntop(AF_INET6, (void *)&po->nd_opt_pi_prefix, pbuf, sizeof (pbuf)); logmsg(LOG_WARNING, "prefix option %s/%u from %s on %s: " "valid %u < pref %u ignored\n", pbuf, plen, abuf, pi->pi_name, validtime, preftime); return (_B_FALSE); } for (pr = pi->pi_prefix_list; pr != NULL; pr = pr->pr_next) { if (pr->pr_prefix_len == plen && prefix_equal(po->nd_opt_pi_prefix, pr->pr_prefix, plen)) { /* Exclude static prefixes and DHCP */ if ((pr->pr_state & PR_STATIC) || (pr->pr_flags & IFF_DHCPRUNNING)) continue; if (pr->pr_flags & IFF_TEMPORARY) { /* * If this address is deprecated and its token * doesn't match the current tmp token, we want * to create a new address with the current * token. So don't count this addr as a match. */ if (!((pr->pr_flags & IFF_DEPRECATED) && !token_equal(pi->pi_tmp_token, pr->pr_address, TMP_TOKEN_BITS))) found_tmp = _B_TRUE; } else { found_pub = _B_TRUE; } (void) incoming_prefix_addrconf_process(pi, pr, opt, from, loopback, _B_FALSE); } } /* * If we have found a matching prefix (for public and, if temp addrs * are enabled, for temporary) already or validtime is zero, we have * nothing to do. */ if (validtime == 0 || (found_pub && (!pi->pi_TmpAddrsEnabled || found_tmp))) return (_B_TRUE); if (!found_pub) { pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, 0); if (pr == NULL) return (_B_TRUE); ret = incoming_prefix_addrconf_process(pi, pr, opt, from, loopback, _B_TRUE); } /* * if processing of the public address failed, * don't bother with the temporary address. */ if (ret == _B_FALSE) return (_B_FALSE); if (pi->pi_TmpAddrsEnabled && !found_tmp) { pr = prefix_create(pi, po->nd_opt_pi_prefix, plen, IFF_TEMPORARY); if (pr == NULL) return (_B_TRUE); ret = incoming_prefix_addrconf_process(pi, pr, opt, from, loopback, _B_TRUE); } return (ret); }
/* * info * depth <x> * seldepth <x> * time <x> * nodes <x> * pv <move1> ... <movei> * score * cp <x> * mate <y> * currmove <move> * hashfull <x> * nps <x> * string <str> */ static int info_parse(Usimsg *msg, const char *s) { const char *p; Token token; int type; int key; int num; p = s; while ((p = token_get(&token, p)) != NULL) { if (token_equal(&token, "depth")) { type = USITYPE_NUM; key = USIOBJ_DEPTH; } else if (token_equal(&token, "seldepth")) { type = USITYPE_NUM; key = USIOBJ_SELDEPTH; } else if (token_equal(&token, "time")) { type = USITYPE_NUM; key = USIOBJ_TIME; } else if (token_equal(&token, "nodes")) { type = USITYPE_NUM; key = USIOBJ_NODES; } else if (token_equal(&token, "pv")) { type = USITYPE_OCT; key = USIOBJ_PV; } else if (token_equal(&token, "score")) { if ((p = token_get(&token, p)) == NULL) return -1; if (token_equal(&token, "cp")) { type = USITYPE_NUM; key = USIOBJ_SCORE_CP; } else if (token_equal(&token, "mate")) { type = USITYPE_NUM; key = USIOBJ_SCORE_MATE; } else { /* rollback */ p = token.s; continue; } } else if (token_equal(&token, "currmove")) { type = USITYPE_STR; key = USIOBJ_CURRMOVE; } else if (token_equal(&token, "hashfull")) { type = USITYPE_NUM; key = USIOBJ_HASHFULL; } else if (token_equal(&token, "nps")) { type = USITYPE_NUM; key = USIOBJ_NPS; } else if (token_equal(&token, "string")) { type = USITYPE_STR; key = USIOBJ_STRING; } else { continue; } switch (type) { case USITYPE_NUM: if ((p = token_get(&token, p)) == NULL) return -1; if (*token.s == '-' && token.len == 1) num = 1 << 31; else num = strtol(token.s, NULL, 10); if (usimsg_pushnum(msg, key, num) != 0) return -1; break; case USITYPE_STR: if ((p = token_get(&token, p)) == NULL) return -1; if (usimsg_pushstr(msg, key, token.s, token.len) != 0) return -1; break; case USITYPE_OCT: if ((p = token_get(&token, p)) == NULL) return -1; if (usimsg_pushstr(msg, key, token.s, strlen(token.s)) != 0) return -1; break; default: break; } } return 0; }
/* * option * name <optionname> type <optiontype> <parameter...> * <optiontype> = * check * spin * combo * button * string * filename * <parameter> = * default <x> * min <x> * max <x> * var <x1> var <x2> ... */ static int option_parse(Usimsg *msg, const char *s) { const char *p; Token token; Tbl *tbl; int type; int num; if ((p = token_get(&token, s)) == NULL) return -1; if (!token_equal(&token, "name")) return -1; if ((p = token_get(&token, p)) == NULL) return -1; if (usimsg_pushstr(msg, USIOBJ_OPTNAME, token.s, token.len) != 0) return -1; if ((p = token_get(&token, p)) == NULL) return -1; if (!token_equal(&token, "type")) return -1; if ((p = token_get(&token, p)) == NULL) return -1; if ((tbl = tbl_find(tbl_option_type, &token)) == NULL) return -1; if (usimsg_pushnum(msg, USIOBJ_TYPE, tbl->id) != 0) return -1; type = tbl->id; while ((p = token_get(&token, p)) != NULL) { if ((tbl = tbl_find(tbl_option, &token)) == NULL) continue; switch (tbl->id) { case USIOBJ_DEFAULT: switch (type) { case USIOPT_CHECK: if ((p = token_get(&token, p)) == NULL) return -1; if (token_equal(&token, "true")) num = 1; else if (token_equal(&token, "false")) num = 0; else return -1; if (usimsg_pushnum(msg, tbl->id, num) != 0) return -1; break; case USIOPT_SPIN: if ((p = token_get(&token, p)) == NULL) return -1; num = strtol(token.s, NULL, 10); if (usimsg_pushnum(msg, tbl->id, num) != 0) return -1; break; case USIOPT_BUTTON: break; case USIOPT_COMBO: case USIOPT_STRING: case USIOPT_FILENAME: if ((p = token_get(&token, p)) == NULL) return -1; if (token_equal(&token, "<empty>")) token.len = 0; if (usimsg_pushstr(msg, tbl->id, token.s, token.len) != 0) return -1; break; default: break; } break; case USIOBJ_MIN: case USIOBJ_MAX: if ((p = token_get(&token, p)) == NULL) return -1; num = strtol(token.s, NULL, 10); if (usimsg_pushnum(msg, tbl->id, num) != 0) return -1; break; case USIOBJ_STRING: if ((p = token_get(&token, p)) == NULL) return -1; if (usimsg_pushstr(msg, tbl->id, token.s, strlen(token.s)) != 0) return -1; break; default: break; } } return 0; }