aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/vsprintf.c199
1 files changed, 152 insertions, 47 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 756ccafa9cec..cb8a112030bb 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -25,6 +25,7 @@
25#include <linux/kallsyms.h> 25#include <linux/kallsyms.h>
26#include <linux/uaccess.h> 26#include <linux/uaccess.h>
27#include <linux/ioport.h> 27#include <linux/ioport.h>
28#include <net/addrconf.h>
28 29
29#include <asm/page.h> /* for PAGE_SIZE */ 30#include <asm/page.h> /* for PAGE_SIZE */
30#include <asm/div64.h> 31#include <asm/div64.h>
@@ -630,60 +631,156 @@ static char *resource_string(char *buf, char *end, struct resource *res,
630} 631}
631 632
632static char *mac_address_string(char *buf, char *end, u8 *addr, 633static char *mac_address_string(char *buf, char *end, u8 *addr,
633 struct printf_spec spec) 634 struct printf_spec spec, const char *fmt)
634{ 635{
635 char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ 636 char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
636 char *p = mac_addr; 637 char *p = mac_addr;
637 int i; 638 int i;
638 639
639 for (i = 0; i < 6; i++) { 640 for (i = 0; i < 6; i++) {
640 p = pack_hex_byte(p, addr[i]); 641 p = pack_hex_byte(p, addr[i]);
641 if (!(spec.flags & SPECIAL) && i != 5) 642 if (fmt[0] == 'M' && i != 5)
642 *p++ = ':'; 643 *p++ = ':';
643 } 644 }
644 *p = '\0'; 645 *p = '\0';
645 spec.flags &= ~SPECIAL;
646 646
647 return string(buf, end, mac_addr, spec); 647 return string(buf, end, mac_addr, spec);
648} 648}
649 649
650static char *ip6_addr_string(char *buf, char *end, u8 *addr, 650static char *ip4_string(char *p, const u8 *addr, bool leading_zeros)
651 struct printf_spec spec) 651{
652 int i;
653
654 for (i = 0; i < 4; i++) {
655 char temp[3]; /* hold each IP quad in reverse order */
656 int digits = put_dec_trunc(temp, addr[i]) - temp;
657 if (leading_zeros) {
658 if (digits < 3)
659 *p++ = '0';
660 if (digits < 2)
661 *p++ = '0';
662 }
663 /* reverse the digits in the quad */
664 while (digits--)
665 *p++ = temp[digits];
666 if (i < 3)
667 *p++ = '.';
668 }
669
670 *p = '\0';
671 return p;
672}
673
674static char *ip6_compressed_string(char *p, const struct in6_addr *addr)
652{ 675{
653 char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */
654 char *p = ip6_addr;
655 int i; 676 int i;
677 int j;
678 int range;
679 unsigned char zerolength[8];
680 int longest = 1;
681 int colonpos = -1;
682 u16 word;
683 u8 hi;
684 u8 lo;
685 bool needcolon = false;
686 bool useIPv4 = ipv6_addr_v4mapped(addr) || ipv6_addr_is_isatap(addr);
687
688 memset(zerolength, 0, sizeof(zerolength));
689
690 if (useIPv4)
691 range = 6;
692 else
693 range = 8;
694
695 /* find position of longest 0 run */
696 for (i = 0; i < range; i++) {
697 for (j = i; j < range; j++) {
698 if (addr->s6_addr16[j] != 0)
699 break;
700 zerolength[i]++;
701 }
702 }
703 for (i = 0; i < range; i++) {
704 if (zerolength[i] > longest) {
705 longest = zerolength[i];
706 colonpos = i;
707 }
708 }
709
710 /* emit address */
711 for (i = 0; i < range; i++) {
712 if (i == colonpos) {
713 if (needcolon || i == 0)
714 *p++ = ':';
715 *p++ = ':';
716 needcolon = false;
717 i += longest - 1;
718 continue;
719 }
720 if (needcolon) {
721 *p++ = ':';
722 needcolon = false;
723 }
724 /* hex u16 without leading 0s */
725 word = ntohs(addr->s6_addr16[i]);
726 hi = word >> 8;
727 lo = word & 0xff;
728 if (hi) {
729 if (hi > 0x0f)
730 p = pack_hex_byte(p, hi);
731 else
732 *p++ = hex_asc_lo(hi);
733 }
734 if (hi || lo > 0x0f)
735 p = pack_hex_byte(p, lo);
736 else
737 *p++ = hex_asc_lo(lo);
738 needcolon = true;
739 }
740
741 if (useIPv4) {
742 if (needcolon)
743 *p++ = ':';
744 p = ip4_string(p, &addr->s6_addr[12], false);
745 }
656 746
747 *p = '\0';
748 return p;
749}
750
751static char *ip6_string(char *p, const struct in6_addr *addr, const char *fmt)
752{
753 int i;
657 for (i = 0; i < 8; i++) { 754 for (i = 0; i < 8; i++) {
658 p = pack_hex_byte(p, addr[2 * i]); 755 p = pack_hex_byte(p, addr->s6_addr[2 * i]);
659 p = pack_hex_byte(p, addr[2 * i + 1]); 756 p = pack_hex_byte(p, addr->s6_addr[2 * i + 1]);
660 if (!(spec.flags & SPECIAL) && i != 7) 757 if (fmt[0] == 'I' && i != 7)
661 *p++ = ':'; 758 *p++ = ':';
662 } 759 }
760
663 *p = '\0'; 761 *p = '\0';
664 spec.flags &= ~SPECIAL; 762 return p;
763}
764
765static char *ip6_addr_string(char *buf, char *end, const u8 *addr,
766 struct printf_spec spec, const char *fmt)
767{
768 char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")];
769
770 if (fmt[0] == 'I' && fmt[2] == 'c')
771 ip6_compressed_string(ip6_addr, (const struct in6_addr *)addr);
772 else
773 ip6_string(ip6_addr, (const struct in6_addr *)addr, fmt);
665 774
666 return string(buf, end, ip6_addr, spec); 775 return string(buf, end, ip6_addr, spec);
667} 776}
668 777
669static char *ip4_addr_string(char *buf, char *end, u8 *addr, 778static char *ip4_addr_string(char *buf, char *end, const u8 *addr,
670 struct printf_spec spec) 779 struct printf_spec spec, const char *fmt)
671{ 780{
672 char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ 781 char ip4_addr[sizeof("255.255.255.255")];
673 char temp[3]; /* hold each IP quad in reverse order */
674 char *p = ip4_addr;
675 int i, digits;
676 782
677 for (i = 0; i < 4; i++) { 783 ip4_string(ip4_addr, addr, fmt[0] == 'i');
678 digits = put_dec_trunc(temp, addr[i]) - temp;
679 /* reverse the digits in the quad */
680 while (digits--)
681 *p++ = temp[digits];
682 if (i != 3)
683 *p++ = '.';
684 }
685 *p = '\0';
686 spec.flags &= ~SPECIAL;
687 784
688 return string(buf, end, ip4_addr, spec); 785 return string(buf, end, ip4_addr, spec);
689} 786}
@@ -702,11 +799,15 @@ static char *ip4_addr_string(char *buf, char *end, u8 *addr,
702 * addresses (not the name nor the flags) 799 * addresses (not the name nor the flags)
703 * - 'M' For a 6-byte MAC address, it prints the address in the 800 * - 'M' For a 6-byte MAC address, it prints the address in the
704 * usual colon-separated hex notation 801 * usual colon-separated hex notation
705 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated 802 * - 'm' For a 6-byte MAC address, it prints the hex address without colons
706 * decimal for v4 and colon separated network-order 16 bit hex for v6) 803 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
707 * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is 804 * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
708 * currently the same 805 * IPv6 uses colon separated network-order 16 bit hex with leading 0's
709 * 806 * - 'i' [46] for 'raw' IPv4/IPv6 addresses
807 * IPv6 omits the colons (01020304...0f)
808 * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
809 * - 'I6c' for IPv6 addresses printed as specified by
810 * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt
710 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 811 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
711 * function pointers are really function descriptors, which contain a 812 * function pointers are really function descriptors, which contain a
712 * pointer to the real address. 813 * pointer to the real address.
@@ -726,20 +827,24 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
726 return symbol_string(buf, end, ptr, spec, *fmt); 827 return symbol_string(buf, end, ptr, spec, *fmt);
727 case 'R': 828 case 'R':
728 return resource_string(buf, end, ptr, spec); 829 return resource_string(buf, end, ptr, spec);
729 case 'm': 830 case 'M': /* Colon separated: 00:01:02:03:04:05 */
730 spec.flags |= SPECIAL; 831 case 'm': /* Contiguous: 000102030405 */
731 /* Fallthrough */ 832 return mac_address_string(buf, end, ptr, spec, fmt);
732 case 'M': 833 case 'I': /* Formatted IP supported
733 return mac_address_string(buf, end, ptr, spec); 834 * 4: 1.2.3.4
734 case 'i': 835 * 6: 0001:0203:...:0708
735 spec.flags |= SPECIAL; 836 * 6c: 1::708 or 1::1.2.3.4
736 /* Fallthrough */ 837 */
737 case 'I': 838 case 'i': /* Contiguous:
738 if (fmt[1] == '6') 839 * 4: 001.002.003.004
739 return ip6_addr_string(buf, end, ptr, spec); 840 * 6: 000102...0f
740 if (fmt[1] == '4') 841 */
741 return ip4_addr_string(buf, end, ptr, spec); 842 switch (fmt[1]) {
742 spec.flags &= ~SPECIAL; 843 case '6':
844 return ip6_addr_string(buf, end, ptr, spec, fmt);
845 case '4':
846 return ip4_addr_string(buf, end, ptr, spec, fmt);
847 }
743 break; 848 break;
744 } 849 }
745 spec.flags |= SMALL; 850 spec.flags |= SMALL;