+static noinline_for_stack
+char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa,
+ struct printf_spec spec, const char *fmt)
+{
+ bool have_p = false, have_s = false, have_f = false, have_c = false;
+ char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") +
+ sizeof(":12345") + sizeof("/123456789") +
+ sizeof("%1234567890")];
+ char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr);
+ const u8 *addr = (const u8 *) &sa->sin6_addr;
+ char fmt6[2] = { fmt[0], '6' };
+ u8 off = 0;
+
+ fmt++;
+ while (isalpha(*++fmt)) {
+ switch (*fmt) {
+ case 'p':
+ have_p = true;
+ break;
+ case 'f':
+ have_f = true;
+ break;
+ case 's':
+ have_s = true;
+ break;
+ case 'c':
+ have_c = true;
+ break;
+ }
+ }
+
+ if (have_p || have_s || have_f) {
+ *p = '[';
+ off = 1;
+ }
+
+ if (fmt6[0] == 'I' && have_c)
+ p = ip6_compressed_string(ip6_addr + off, addr);
+ else
+ p = ip6_string(ip6_addr + off, addr, fmt6);
+
+ if (have_p || have_s || have_f)
+ *p++ = ']';
+
+ if (have_p) {
+ *p++ = ':';
+ p = number(p, pend, ntohs(sa->sin6_port), spec);
+ }
+ if (have_f) {
+ *p++ = '/';
+ p = number(p, pend, ntohl(sa->sin6_flowinfo &
+ IPV6_FLOWINFO_MASK), spec);
+ }
+ if (have_s) {
+ *p++ = '%';
+ p = number(p, pend, sa->sin6_scope_id, spec);
+ }
+ *p = '\0';
+
+ return string(buf, end, ip6_addr, spec);
+}
+
+static noinline_for_stack
+char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa,
+ struct printf_spec spec, const char *fmt)
+{
+ bool have_p = false;
+ char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")];
+ char *pend = ip4_addr + sizeof(ip4_addr);
+ const u8 *addr = (const u8 *) &sa->sin_addr.s_addr;
+ char fmt4[3] = { fmt[0], '4', 0 };
+
+ fmt++;
+ while (isalpha(*++fmt)) {
+ switch (*fmt) {
+ case 'p':
+ have_p = true;
+ break;
+ case 'h':
+ case 'l':
+ case 'n':
+ case 'b':
+ fmt4[2] = *fmt;
+ break;
+ }
+ }
+
+ p = ip4_string(ip4_addr, addr, fmt4);
+ if (have_p) {
+ *p++ = ':';
+ p = number(p, pend, ntohs(sa->sin_port), spec);
+ }
+ *p = '\0';
+
+ return string(buf, end, ip4_addr, spec);
+}
+