mirror of
				https://git.kernel.org/pub/scm/linux/kernel/git/chenhuacai/linux-loongson
				synced 2025-10-31 22:26:12 +00:00 
			
		
		
		
	 75b31c3351
			
		
	
	
		75b31c3351
		
	
	
	
	
		
			
			I don't know of any Andy Kleen's but I do know a Andi Kleen. Signed-off-by: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: David S. Miller <davem@davemloft.net>
		
			
				
	
	
		
			407 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			407 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *	Generic address resultion entity
 | |
|  *
 | |
|  *	Authors:
 | |
|  *	net_random Alan Cox
 | |
|  *	net_ratelimit Andi Kleen
 | |
|  *	in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project
 | |
|  *
 | |
|  *	Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
 | |
|  *
 | |
|  *	This program is free software; you can redistribute it and/or
 | |
|  *      modify it under the terms of the GNU General Public License
 | |
|  *      as published by the Free Software Foundation; either version
 | |
|  *      2 of the License, or (at your option) any later version.
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/jiffies.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/inet.h>
 | |
| #include <linux/mm.h>
 | |
| #include <linux/net.h>
 | |
| #include <linux/string.h>
 | |
| #include <linux/types.h>
 | |
| #include <linux/random.h>
 | |
| #include <linux/percpu.h>
 | |
| #include <linux/init.h>
 | |
| 
 | |
| #include <asm/byteorder.h>
 | |
| #include <asm/system.h>
 | |
| #include <asm/uaccess.h>
 | |
| 
 | |
| /*
 | |
|   This is a maximally equidistributed combined Tausworthe generator
 | |
|   based on code from GNU Scientific Library 1.5 (30 Jun 2004)
 | |
| 
 | |
|    x_n = (s1_n ^ s2_n ^ s3_n) 
 | |
| 
 | |
|    s1_{n+1} = (((s1_n & 4294967294) <<12) ^ (((s1_n <<13) ^ s1_n) >>19))
 | |
|    s2_{n+1} = (((s2_n & 4294967288) << 4) ^ (((s2_n << 2) ^ s2_n) >>25))
 | |
|    s3_{n+1} = (((s3_n & 4294967280) <<17) ^ (((s3_n << 3) ^ s3_n) >>11))
 | |
| 
 | |
|    The period of this generator is about 2^88.
 | |
| 
 | |
|    From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe
 | |
|    Generators", Mathematics of Computation, 65, 213 (1996), 203--213.
 | |
| 
 | |
|    This is available on the net from L'Ecuyer's home page,
 | |
| 
 | |
|    http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps
 | |
|    ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps 
 | |
| 
 | |
|    There is an erratum in the paper "Tables of Maximally
 | |
|    Equidistributed Combined LFSR Generators", Mathematics of
 | |
|    Computation, 68, 225 (1999), 261--269:
 | |
|    http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps
 | |
| 
 | |
|         ... the k_j most significant bits of z_j must be non-
 | |
|         zero, for each j. (Note: this restriction also applies to the 
 | |
|         computer code given in [4], but was mistakenly not mentioned in
 | |
|         that paper.)
 | |
|    
 | |
|    This affects the seeding procedure by imposing the requirement
 | |
|    s1 > 1, s2 > 7, s3 > 15.
 | |
| 
 | |
| */
 | |
| struct nrnd_state {
 | |
| 	u32 s1, s2, s3;
 | |
| };
 | |
| 
 | |
| static DEFINE_PER_CPU(struct nrnd_state, net_rand_state);
 | |
| 
 | |
| static u32 __net_random(struct nrnd_state *state)
 | |
| {
 | |
| #define TAUSWORTHE(s,a,b,c,d) ((s&c)<<d) ^ (((s <<a) ^ s)>>b)
 | |
| 
 | |
| 	state->s1 = TAUSWORTHE(state->s1, 13, 19, 4294967294UL, 12);
 | |
| 	state->s2 = TAUSWORTHE(state->s2, 2, 25, 4294967288UL, 4);
 | |
| 	state->s3 = TAUSWORTHE(state->s3, 3, 11, 4294967280UL, 17);
 | |
| 
 | |
| 	return (state->s1 ^ state->s2 ^ state->s3);
 | |
| }
 | |
| 
 | |
| static void __net_srandom(struct nrnd_state *state, unsigned long s)
 | |
| {
 | |
| 	if (s == 0)
 | |
| 		s = 1;      /* default seed is 1 */
 | |
| 
 | |
| #define LCG(n) (69069 * n)
 | |
| 	state->s1 = LCG(s);
 | |
| 	state->s2 = LCG(state->s1);
 | |
| 	state->s3 = LCG(state->s2);
 | |
| 
 | |
| 	/* "warm it up" */
 | |
| 	__net_random(state);
 | |
| 	__net_random(state);
 | |
| 	__net_random(state);
 | |
| 	__net_random(state);
 | |
| 	__net_random(state);
 | |
| 	__net_random(state);
 | |
| }
 | |
| 
 | |
| 
 | |
| unsigned long net_random(void)
 | |
| {
 | |
| 	unsigned long r;
 | |
| 	struct nrnd_state *state = &get_cpu_var(net_rand_state);
 | |
| 	r = __net_random(state);
 | |
| 	put_cpu_var(state);
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| 
 | |
| void net_srandom(unsigned long entropy)
 | |
| {
 | |
| 	struct nrnd_state *state = &get_cpu_var(net_rand_state);
 | |
| 	__net_srandom(state, state->s1^entropy);
 | |
| 	put_cpu_var(state);
 | |
| }
 | |
| 
 | |
| void __init net_random_init(void)
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	for_each_possible_cpu(i) {
 | |
| 		struct nrnd_state *state = &per_cpu(net_rand_state,i);
 | |
| 		__net_srandom(state, i+jiffies);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int net_random_reseed(void)
 | |
| {
 | |
| 	int i;
 | |
| 	unsigned long seed;
 | |
| 
 | |
| 	for_each_possible_cpu(i) {
 | |
| 		struct nrnd_state *state = &per_cpu(net_rand_state,i);
 | |
| 
 | |
| 		get_random_bytes(&seed, sizeof(seed));
 | |
| 		__net_srandom(state, seed);
 | |
| 	}
 | |
| 	return 0;
 | |
| }
 | |
| late_initcall(net_random_reseed);
 | |
| 
 | |
| int net_msg_cost = 5*HZ;
 | |
| int net_msg_burst = 10;
 | |
| 
 | |
| /* 
 | |
|  * All net warning printk()s should be guarded by this function.
 | |
|  */ 
 | |
| int net_ratelimit(void)
 | |
| {
 | |
| 	return __printk_ratelimit(net_msg_cost, net_msg_burst);
 | |
| }
 | |
| 
 | |
| EXPORT_SYMBOL(net_random);
 | |
| EXPORT_SYMBOL(net_ratelimit);
 | |
| EXPORT_SYMBOL(net_srandom);
 | |
| 
 | |
| /*
 | |
|  * Convert an ASCII string to binary IP.
 | |
|  * This is outside of net/ipv4/ because various code that uses IP addresses
 | |
|  * is otherwise not dependent on the TCP/IP stack.
 | |
|  */
 | |
| 
 | |
| __be32 in_aton(const char *str)
 | |
| {
 | |
| 	unsigned long l;
 | |
| 	unsigned int val;
 | |
| 	int i;
 | |
| 
 | |
| 	l = 0;
 | |
| 	for (i = 0; i < 4; i++)
 | |
| 	{
 | |
| 		l <<= 8;
 | |
| 		if (*str != '\0')
 | |
| 		{
 | |
| 			val = 0;
 | |
| 			while (*str != '\0' && *str != '.' && *str != '\n')
 | |
| 			{
 | |
| 				val *= 10;
 | |
| 				val += *str - '0';
 | |
| 				str++;
 | |
| 			}
 | |
| 			l |= val;
 | |
| 			if (*str != '\0')
 | |
| 				str++;
 | |
| 		}
 | |
| 	}
 | |
| 	return(htonl(l));
 | |
| }
 | |
| 
 | |
| EXPORT_SYMBOL(in_aton);
 | |
| 
 | |
| #define IN6PTON_XDIGIT		0x00010000
 | |
| #define IN6PTON_DIGIT		0x00020000
 | |
| #define IN6PTON_COLON_MASK	0x00700000
 | |
| #define IN6PTON_COLON_1		0x00100000	/* single : requested */
 | |
| #define IN6PTON_COLON_2		0x00200000	/* second : requested */
 | |
| #define IN6PTON_COLON_1_2	0x00400000	/* :: requested */
 | |
| #define IN6PTON_DOT		0x00800000	/* . */
 | |
| #define IN6PTON_DELIM		0x10000000
 | |
| #define IN6PTON_NULL		0x20000000	/* first/tail */
 | |
| #define IN6PTON_UNKNOWN		0x40000000
 | |
| 
 | |
| static inline int digit2bin(char c, char delim)
 | |
| {
 | |
| 	if (c == delim || c == '\0')
 | |
| 		return IN6PTON_DELIM;
 | |
| 	if (c == '.')
 | |
| 		return IN6PTON_DOT;
 | |
| 	if (c >= '0' && c <= '9')
 | |
| 		return (IN6PTON_DIGIT | (c - '0'));
 | |
| 	return IN6PTON_UNKNOWN;
 | |
| }
 | |
| 
 | |
| static inline int xdigit2bin(char c, char delim)
 | |
| {
 | |
| 	if (c == delim || c == '\0')
 | |
| 		return IN6PTON_DELIM;
 | |
| 	if (c == ':')
 | |
| 		return IN6PTON_COLON_MASK;
 | |
| 	if (c == '.')
 | |
| 		return IN6PTON_DOT;
 | |
| 	if (c >= '0' && c <= '9')
 | |
| 		return (IN6PTON_XDIGIT | IN6PTON_DIGIT| (c - '0'));
 | |
| 	if (c >= 'a' && c <= 'f')
 | |
| 		return (IN6PTON_XDIGIT | (c - 'a' + 10));
 | |
| 	if (c >= 'A' && c <= 'F')
 | |
| 		return (IN6PTON_XDIGIT | (c - 'A' + 10));
 | |
| 	return IN6PTON_UNKNOWN;
 | |
| }
 | |
| 
 | |
| int in4_pton(const char *src, int srclen,
 | |
| 	     u8 *dst,
 | |
| 	     char delim, const char **end)
 | |
| {
 | |
| 	const char *s;
 | |
| 	u8 *d;
 | |
| 	u8 dbuf[4];
 | |
| 	int ret = 0;
 | |
| 	int i;
 | |
| 	int w = 0;
 | |
| 
 | |
| 	if (srclen < 0)
 | |
| 		srclen = strlen(src);
 | |
| 	s = src;
 | |
| 	d = dbuf;
 | |
| 	i = 0;
 | |
| 	while(1) {
 | |
| 		int c;
 | |
| 		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
 | |
| 		if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
 | |
| 			goto out;
 | |
| 		}
 | |
| 		if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
 | |
| 			if (w == 0)
 | |
| 				goto out;
 | |
| 			*d++ = w & 0xff;
 | |
| 			w = 0;
 | |
| 			i++;
 | |
| 			if (c & IN6PTON_DELIM) {
 | |
| 				if (i != 4)
 | |
| 					goto out;
 | |
| 				break;
 | |
| 			}
 | |
| 			goto cont;
 | |
| 		}
 | |
| 		w = (w * 10) + c;
 | |
| 		if ((w & 0xffff) > 255) {
 | |
| 			goto out;
 | |
| 		}
 | |
| cont:
 | |
| 		if (i >= 4)
 | |
| 			goto out;
 | |
| 		s++;
 | |
| 		srclen--;
 | |
| 	}
 | |
| 	ret = 1;
 | |
| 	memcpy(dst, dbuf, sizeof(dbuf));
 | |
| out:
 | |
| 	if (end)
 | |
| 		*end = s;
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| EXPORT_SYMBOL(in4_pton);
 | |
| 
 | |
| int in6_pton(const char *src, int srclen,
 | |
| 	     u8 *dst,
 | |
| 	     char delim, const char **end)
 | |
| {
 | |
| 	const char *s, *tok = NULL;
 | |
| 	u8 *d, *dc = NULL;
 | |
| 	u8 dbuf[16];
 | |
| 	int ret = 0;
 | |
| 	int i;
 | |
| 	int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
 | |
| 	int w = 0;
 | |
| 
 | |
| 	memset(dbuf, 0, sizeof(dbuf));
 | |
| 
 | |
| 	s = src;
 | |
| 	d = dbuf;
 | |
| 	if (srclen < 0)
 | |
| 		srclen = strlen(src);
 | |
| 
 | |
| 	while (1) {
 | |
| 		int c;
 | |
| 
 | |
| 		c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
 | |
| 		if (!(c & state))
 | |
| 			goto out;
 | |
| 		if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
 | |
| 			/* process one 16-bit word */
 | |
| 			if (!(state & IN6PTON_NULL)) {
 | |
| 				*d++ = (w >> 8) & 0xff;
 | |
| 				*d++ = w & 0xff;
 | |
| 			}
 | |
| 			w = 0;
 | |
| 			if (c & IN6PTON_DELIM) {
 | |
| 				/* We've processed last word */
 | |
| 				break;
 | |
| 			}
 | |
| 			/*
 | |
| 			 * COLON_1 => XDIGIT
 | |
| 			 * COLON_2 => XDIGIT|DELIM
 | |
| 			 * COLON_1_2 => COLON_2
 | |
| 			 */
 | |
| 			switch (state & IN6PTON_COLON_MASK) {
 | |
| 			case IN6PTON_COLON_2:
 | |
| 				dc = d;
 | |
| 				state = IN6PTON_XDIGIT | IN6PTON_DELIM;
 | |
| 				if (dc - dbuf >= sizeof(dbuf))
 | |
| 					state |= IN6PTON_NULL;
 | |
| 				break;
 | |
| 			case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
 | |
| 				state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
 | |
| 				break;
 | |
| 			case IN6PTON_COLON_1:
 | |
| 				state = IN6PTON_XDIGIT;
 | |
| 				break;
 | |
| 			case IN6PTON_COLON_1_2:
 | |
| 				state = IN6PTON_COLON_2;
 | |
| 				break;
 | |
| 			default:
 | |
| 				state = 0;
 | |
| 			}
 | |
| 			tok = s + 1;
 | |
| 			goto cont;
 | |
| 		}
 | |
| 
 | |
| 		if (c & IN6PTON_DOT) {
 | |
| 			ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
 | |
| 			if (ret > 0) {
 | |
| 				d += 4;
 | |
| 				break;
 | |
| 			}
 | |
| 			goto out;
 | |
| 		}
 | |
| 
 | |
| 		w = (w << 4) | (0xff & c);
 | |
| 		state = IN6PTON_COLON_1 | IN6PTON_DELIM;
 | |
| 		if (!(w & 0xf000)) {
 | |
| 			state |= IN6PTON_XDIGIT;
 | |
| 		}
 | |
| 		if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
 | |
| 			state |= IN6PTON_COLON_1_2;
 | |
| 			state &= ~IN6PTON_DELIM;
 | |
| 		}
 | |
| 		if (d + 2 >= dbuf + sizeof(dbuf)) {
 | |
| 			state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
 | |
| 		}
 | |
| cont:
 | |
| 		if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
 | |
| 		    d + 4 == dbuf + sizeof(dbuf)) {
 | |
| 			state |= IN6PTON_DOT;
 | |
| 		}
 | |
| 		if (d >= dbuf + sizeof(dbuf)) {
 | |
| 			state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
 | |
| 		}
 | |
| 		s++;
 | |
| 		srclen--;
 | |
| 	}
 | |
| 
 | |
| 	i = 15; d--;
 | |
| 
 | |
| 	if (dc) {
 | |
| 		while(d >= dc)
 | |
| 			dst[i--] = *d--;
 | |
| 		while(i >= dc - dbuf)
 | |
| 			dst[i--] = 0;
 | |
| 		while(i >= 0)
 | |
| 			dst[i--] = *d--;
 | |
| 	} else
 | |
| 		memcpy(dst, dbuf, sizeof(dbuf));
 | |
| 
 | |
| 	ret = 1;
 | |
| out:
 | |
| 	if (end)
 | |
| 		*end = s;
 | |
| 	return ret;
 | |
| }
 | |
| 
 | |
| EXPORT_SYMBOL(in6_pton);
 |