Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
10795980
Commit
10795980
authored
Apr 07, 2003
by
Alan Cox
Committed by
Linus Torvalds
Apr 07, 2003
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] first pass at fixing strip for 2.5
parent
2f5b7e8c
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
1973 additions
and
1983 deletions
+1973
-1983
drivers/net/wireless/strip.c
drivers/net/wireless/strip.c
+1973
-1983
No files found.
drivers/net/wireless/strip.c
View file @
10795980
...
@@ -69,9 +69,9 @@
...
@@ -69,9 +69,9 @@
*/
*/
#ifdef MODULE
#ifdef MODULE
static
const
char
StripVersion
[]
=
"1.3-STUART.CHESHIRE-MODULAR"
;
static
const
char
StripVersion
[]
=
"1.3
A
-STUART.CHESHIRE-MODULAR"
;
#else
#else
static
const
char
StripVersion
[]
=
"1.3-STUART.CHESHIRE"
;
static
const
char
StripVersion
[]
=
"1.3
A
-STUART.CHESHIRE"
;
#endif
#endif
#define TICKLE_TIMERS 0
#define TICKLE_TIMERS 0
...
@@ -89,18 +89,7 @@ static const char StripVersion[] = "1.3-STUART.CHESHIRE";
...
@@ -89,18 +89,7 @@ static const char StripVersion[] = "1.3-STUART.CHESHIRE";
#include <asm/uaccess.h>
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <asm/bitops.h>
/*
* isdigit() and isspace() use the ctype[] array, which is not available
* to kernel modules. If compiling as a module, use a local definition
* of isdigit() and isspace() until _ctype is added to ksyms.
*/
#ifdef MODULE
# define isdigit(c) ('0' <= (c) && (c) <= '9')
# define isspace(c) ((c) == ' ' || (c) == '\t')
#else
# include <linux/ctype.h>
# include <linux/ctype.h>
#endif
#include <linux/string.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/interrupt.h>
...
@@ -131,8 +120,7 @@ static const char StripVersion[] = "1.3-STUART.CHESHIRE";
...
@@ -131,8 +120,7 @@ static const char StripVersion[] = "1.3-STUART.CHESHIRE";
* Starmode packet.
* Starmode packet.
*/
*/
typedef
union
typedef
union
{
{
__u8
c
[
4
];
__u8
c
[
4
];
__u32
l
;
__u32
l
;
}
MetricomKey
;
}
MetricomKey
;
...
@@ -142,8 +130,7 @@ typedef union
...
@@ -142,8 +130,7 @@ typedef union
* a single 32-bit long (which is convenient for assignment, equality testing etc.)
* a single 32-bit long (which is convenient for assignment, equality testing etc.)
*/
*/
typedef
union
typedef
union
{
{
__u8
b
[
4
];
__u8
b
[
4
];
__u32
l
;
__u32
l
;
}
IPaddr
;
}
IPaddr
;
...
@@ -153,8 +140,7 @@ typedef union
...
@@ -153,8 +140,7 @@ typedef union
* a Metricom address.
* a Metricom address.
*/
*/
typedef
struct
typedef
struct
{
{
__u8
c
[
24
];
__u8
c
[
24
];
}
MetricomAddressString
;
}
MetricomAddressString
;
...
@@ -173,21 +159,18 @@ typedef struct
...
@@ -173,21 +159,18 @@ typedef struct
* already understands Ethernet headers.
* already understands Ethernet headers.
*/
*/
typedef
struct
typedef
struct
{
{
MetricomAddress
dst_addr
;
/* Destination address, e.g. "0000-1234" */
MetricomAddress
dst_addr
;
/* Destination address, e.g. "0000-1234" */
MetricomAddress
src_addr
;
/* Source address, e.g. "0000-5678" */
MetricomAddress
src_addr
;
/* Source address, e.g. "0000-5678" */
unsigned
short
protocol
;
/* The protocol type, using Ethernet codes */
unsigned
short
protocol
;
/* The protocol type, using Ethernet codes */
}
STRIP_Header
;
}
STRIP_Header
;
typedef
struct
typedef
struct
{
{
char
c
[
60
];
char
c
[
60
];
}
MetricomNode
;
}
MetricomNode
;
#define NODE_TABLE_SIZE 32
#define NODE_TABLE_SIZE 32
typedef
struct
typedef
struct
{
{
struct
timeval
timestamp
;
struct
timeval
timestamp
;
int
num_nodes
;
int
num_nodes
;
MetricomNode
node
[
NODE_TABLE_SIZE
];
MetricomNode
node
[
NODE_TABLE_SIZE
];
...
@@ -198,48 +181,42 @@ enum { FALSE = 0, TRUE = 1 };
...
@@ -198,48 +181,42 @@ enum { FALSE = 0, TRUE = 1 };
/*
/*
* Holds the radio's firmware version.
* Holds the radio's firmware version.
*/
*/
typedef
struct
typedef
struct
{
{
char
c
[
50
];
char
c
[
50
];
}
FirmwareVersion
;
}
FirmwareVersion
;
/*
/*
* Holds the radio's serial number.
* Holds the radio's serial number.
*/
*/
typedef
struct
typedef
struct
{
{
char
c
[
18
];
char
c
[
18
];
}
SerialNumber
;
}
SerialNumber
;
/*
/*
* Holds the radio's battery voltage.
* Holds the radio's battery voltage.
*/
*/
typedef
struct
typedef
struct
{
{
char
c
[
11
];
char
c
[
11
];
}
BatteryVoltage
;
}
BatteryVoltage
;
typedef
struct
typedef
struct
{
{
char
c
[
8
];
char
c
[
8
];
}
char8
;
}
char8
;
enum
enum
{
{
NoStructure
=
0
,
/* Really old firmware */
NoStructure
=
0
,
/* Really old firmware */
StructuredMessages
=
1
,
/* Parsable AT response msgs */
StructuredMessages
=
1
,
/* Parsable AT response msgs */
ChecksummedMessages
=
2
/* Parsable AT response msgs with checksums */
ChecksummedMessages
=
2
/* Parsable AT response msgs with checksums */
}
FirmwareLevel
;
}
FirmwareLevel
;
struct
strip
struct
strip
{
{
int
magic
;
int
magic
;
/*
/*
* These are pointers to the malloc()ed frame buffers.
* These are pointers to the malloc()ed frame buffers.
*/
*/
unsigned
char
*
rx_buff
;
/* buffer for received IP packet
*/
unsigned
char
*
rx_buff
;
/* buffer for received IP packet
*/
unsigned
char
*
sx_buff
;
/* buffer for received serial data
*/
unsigned
char
*
sx_buff
;
/* buffer for received serial data
*/
int
sx_count
;
/* received serial data counter */
int
sx_count
;
/* received serial data counter */
int
sx_size
;
/* Serial buffer size */
int
sx_size
;
/* Serial buffer size */
unsigned
char
*
tx_buff
;
/* transmitter buffer */
unsigned
char
*
tx_buff
;
/* transmitter buffer */
...
@@ -283,7 +260,7 @@ struct strip
...
@@ -283,7 +260,7 @@ struct strip
*/
*/
struct
strip
*
next
;
/* The next struct in the list */
struct
strip
*
next
;
/* The next struct in the list */
struct
strip
**
referrer
;
/* The pointer that points to us
*/
struct
strip
**
referrer
;
/* The pointer that points to us
*/
int
discard
;
/* Set if serial error */
int
discard
;
/* Set if serial error */
int
working
;
/* Is radio working correctly? */
int
working
;
/* Is radio working correctly? */
int
firmware_level
;
/* Message structuring level */
int
firmware_level
;
/* Message structuring level */
...
@@ -292,7 +269,7 @@ struct strip
...
@@ -292,7 +269,7 @@ struct strip
int
mtu
;
/* Our mtu (to spot changes!) */
int
mtu
;
/* Our mtu (to spot changes!) */
long
watchdog_doprobe
;
/* Next time to test the radio */
long
watchdog_doprobe
;
/* Next time to test the radio */
long
watchdog_doreset
;
/* Time to do next reset */
long
watchdog_doreset
;
/* Time to do next reset */
long
gratuitous_arp
;
/* Time to send next ARP refresh
*/
long
gratuitous_arp
;
/* Time to send next ARP refresh
*/
long
arp_interval
;
/* Next ARP interval */
long
arp_interval
;
/* Next ARP interval */
struct
timer_list
idle_timer
;
/* For periodic wakeup calls */
struct
timer_list
idle_timer
;
/* For periodic wakeup calls */
MetricomAddress
true_dev_addr
;
/* True address of radio */
MetricomAddress
true_dev_addr
;
/* True address of radio */
...
@@ -406,17 +383,19 @@ static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery volta
...
@@ -406,17 +383,19 @@ static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery volta
static
const
char
CommandString3
[]
=
"*&COMMAND*ATS300?"
;
/* Query version information */
static
const
char
CommandString3
[]
=
"*&COMMAND*ATS300?"
;
/* Query version information */
static
const
char
CommandString4
[]
=
"*&COMMAND*ATS311?"
;
/* Query poletop list */
static
const
char
CommandString4
[]
=
"*&COMMAND*ATS311?"
;
/* Query poletop list */
static
const
char
CommandString5
[]
=
"*&COMMAND*AT~LA"
;
/* Query portables list */
static
const
char
CommandString5
[]
=
"*&COMMAND*AT~LA"
;
/* Query portables list */
typedef
struct
{
const
char
*
string
;
long
length
;
}
StringDescriptor
;
typedef
struct
{
const
char
*
string
;
static
const
StringDescriptor
CommandString
[]
=
long
length
;
{
}
StringDescriptor
;
{
CommandString0
,
sizeof
(
CommandString0
)
-
1
},
{
CommandString1
,
sizeof
(
CommandString1
)
-
1
},
static
const
StringDescriptor
CommandString
[]
=
{
{
CommandString2
,
sizeof
(
CommandString2
)
-
1
},
{
CommandString0
,
sizeof
(
CommandString0
)
-
1
},
{
CommandString3
,
sizeof
(
CommandString3
)
-
1
},
{
CommandString1
,
sizeof
(
CommandString1
)
-
1
},
{
CommandString4
,
sizeof
(
CommandString4
)
-
1
},
{
CommandString2
,
sizeof
(
CommandString2
)
-
1
},
{
CommandString5
,
sizeof
(
CommandString5
)
-
1
}
{
CommandString3
,
sizeof
(
CommandString3
)
-
1
},
};
{
CommandString4
,
sizeof
(
CommandString4
)
-
1
},
{
CommandString5
,
sizeof
(
CommandString5
)
-
1
}
};
#define GOT_ALL_RADIO_INFO(S) \
#define GOT_ALL_RADIO_INFO(S) \
((S)->firmware_version.c[0] && \
((S)->firmware_version.c[0] && \
...
@@ -426,14 +405,15 @@ static const StringDescriptor CommandString[] =
...
@@ -426,14 +405,15 @@ static const StringDescriptor CommandString[] =
static
const
char
hextable
[
16
]
=
"0123456789ABCDEF"
;
static
const
char
hextable
[
16
]
=
"0123456789ABCDEF"
;
static
const
MetricomAddress
zero_address
;
static
const
MetricomAddress
zero_address
;
static
const
MetricomAddress
broadcast_address
=
{
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
}
};
static
const
MetricomAddress
broadcast_address
=
{
{
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
,
0xFF
}
};
static
const
MetricomKey
SIP0Key
=
{
{
"SIP0"
}
};
static
const
MetricomKey
SIP0Key
=
{
{
"SIP0"
}
};
static
const
MetricomKey
ARP0Key
=
{
{
"ARP0"
}
};
static
const
MetricomKey
ARP0Key
=
{
{
"ARP0"
}
};
static
const
MetricomKey
ATR_Key
=
{
{
"ATR "
}
};
static
const
MetricomKey
ATR_Key
=
{
{
"ATR "
}
};
static
const
MetricomKey
ACK_Key
=
{
{
"ACK_"
}
};
static
const
MetricomKey
ACK_Key
=
{
{
"ACK_"
}
};
static
const
MetricomKey
INF_Key
=
{
{
"INF_"
}
};
static
const
MetricomKey
INF_Key
=
{
{
"INF_"
}
};
static
const
MetricomKey
ERR_Key
=
{
{
"ERR_"
}
};
static
const
MetricomKey
ERR_Key
=
{
{
"ERR_"
}
};
static
const
long
MaxARPInterval
=
60
*
HZ
;
/* One minute */
static
const
long
MaxARPInterval
=
60
*
HZ
;
/* One minute */
...
@@ -451,12 +431,11 @@ static const unsigned short DEFAULT_STRIP_MTU = 1152;
...
@@ -451,12 +431,11 @@ static const unsigned short DEFAULT_STRIP_MTU = 1152;
static
const
int
STRIP_MAGIC
=
0x5303
;
static
const
int
STRIP_MAGIC
=
0x5303
;
static
const
long
LongTime
=
0x7FFFFFFF
;
static
const
long
LongTime
=
0x7FFFFFFF
;
/************************************************************************/
/************************************************************************/
/* Global variables */
/* Global variables */
static
struct
strip
*
struct_strip_list
;
static
struct
strip
*
struct_strip_list
;
static
spinlock_t
strip_lock
;
/************************************************************************/
/************************************************************************/
/* Macros */
/* Macros */
...
@@ -486,32 +465,16 @@ static struct strip *struct_strip_list;
...
@@ -486,32 +465,16 @@ static struct strip *struct_strip_list;
/************************************************************************/
/************************************************************************/
/* Utility routines */
/* Utility routines */
typedef
unsigned
long
InterruptStatus
;
static
int
arp_query
(
unsigned
char
*
haddr
,
u32
paddr
,
struct
net_device
*
dev
)
static
inline
InterruptStatus
DisableInterrupts
(
void
)
{
InterruptStatus
x
;
save_flags
(
x
);
cli
();
return
(
x
);
}
static
inline
void
RestoreInterrupts
(
InterruptStatus
x
)
{
restore_flags
(
x
);
}
static
int
arp_query
(
unsigned
char
*
haddr
,
u32
paddr
,
struct
net_device
*
dev
)
{
{
struct
neighbour
*
neighbor_entry
;
struct
neighbour
*
neighbor_entry
;
neighbor_entry
=
neigh_lookup
(
&
arp_tbl
,
&
paddr
,
dev
);
neighbor_entry
=
neigh_lookup
(
&
arp_tbl
,
&
paddr
,
dev
);
if
(
neighbor_entry
!=
NULL
)
if
(
neighbor_entry
!=
NULL
)
{
{
neighbor_entry
->
used
=
jiffies
;
neighbor_entry
->
used
=
jiffies
;
if
(
neighbor_entry
->
nud_state
&
NUD_VALID
)
if
(
neighbor_entry
->
nud_state
&
NUD_VALID
)
{
{
memcpy
(
haddr
,
neighbor_entry
->
ha
,
dev
->
addr_len
);
memcpy
(
haddr
,
neighbor_entry
->
ha
,
dev
->
addr_len
);
return
1
;
return
1
;
}
}
...
@@ -519,67 +482,36 @@ static int arp_query(unsigned char *haddr, u32 paddr, struct net_device * dev)
...
@@ -519,67 +482,36 @@ static int arp_query(unsigned char *haddr, u32 paddr, struct net_device * dev)
return
0
;
return
0
;
}
}
static
void
DumpData
(
char
*
msg
,
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
DumpData
(
char
*
msg
,
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
static
const
int
MAX_DumpData
=
80
;
static
const
int
MAX_DumpData
=
80
;
__u8
pkt_text
[
MAX_DumpData
],
*
p
=
pkt_text
;
__u8
pkt_text
[
MAX_DumpData
],
*
p
=
pkt_text
;
*
p
++
=
'\"'
;
*
p
++
=
'\"'
;
while
(
ptr
<
end
&&
p
<
&
pkt_text
[
MAX_DumpData
-
4
])
while
(
ptr
<
end
&&
p
<
&
pkt_text
[
MAX_DumpData
-
4
])
{
{
if
(
*
ptr
==
'\\'
)
{
if
(
*
ptr
==
'\\'
)
{
*
p
++
=
'\\'
;
*
p
++
=
'\\'
;
*
p
++
=
'\\'
;
*
p
++
=
'\\'
;
}
}
else
{
else
if
(
*
ptr
>=
32
&&
*
ptr
<=
126
)
{
{
if
(
*
ptr
>=
32
&&
*
ptr
<=
126
)
{
*
p
++
=
*
ptr
;
*
p
++
=
*
ptr
;
}
}
else
{
else
{
sprintf
(
p
,
"
\\
%02X"
,
*
ptr
);
sprintf
(
p
,
"
\\
%02X"
,
*
ptr
);
p
+=
3
;
p
+=
3
;
}
}
}
}
ptr
++
;
ptr
++
;
}
}
if
(
ptr
==
end
)
if
(
ptr
==
end
)
{
*
p
++
=
'\"'
;
*
p
++
=
'\"'
;
}
*
p
++
=
0
;
*
p
++
=
0
;
printk
(
KERN_INFO
"%s: %-13s%s
\n
"
,
strip_info
->
dev
.
name
,
msg
,
pkt_text
);
printk
(
KERN_INFO
"%s: %-13s%s
\n
"
,
strip_info
->
dev
.
name
,
msg
,
pkt_text
);
}
}
#if 0
static void HexDump(char *msg, struct strip *strip_info, __u8 *start, __u8 *end)
{
__u8 *ptr = start;
printk(KERN_INFO "%s: %s: %d bytes\n", strip_info->dev.name, msg, end-ptr);
while (ptr < end)
{
long offset = ptr - start;
__u8 text[80], *p = text;
while (ptr < end && p < &text[16*3])
{
*p++ = hextable[*ptr >> 4];
*p++ = hextable[*ptr++ & 0xF];
*p++ = ' ';
}
p[-1] = 0;
printk(KERN_INFO "%s: %4lX %s\n", strip_info->dev.name, offset, text);
}
}
#endif
/************************************************************************/
/************************************************************************/
/* Byte stuffing/unstuffing routines */
/* Byte stuffing/unstuffing routines */
...
@@ -592,8 +524,7 @@ static void HexDump(char *msg, struct strip *strip_info, __u8 *start, __u8 *end)
...
@@ -592,8 +524,7 @@ static void HexDump(char *msg, struct strip *strip_info, __u8 *start, __u8 *end)
* C0-FF Run of 1-64 zeroes (ASCII 0)
* C0-FF Run of 1-64 zeroes (ASCII 0)
*/
*/
typedef
enum
typedef
enum
{
{
Stuff_Diff
=
0x00
,
Stuff_Diff
=
0x00
,
Stuff_DiffZero
=
0x40
,
Stuff_DiffZero
=
0x40
,
Stuff_Same
=
0x80
,
Stuff_Same
=
0x80
,
...
@@ -622,17 +553,17 @@ typedef enum
...
@@ -622,17 +553,17 @@ typedef enum
#define StuffData_FinishBlock(X) \
#define StuffData_FinishBlock(X) \
(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
(*code_ptr = (X) ^ Stuff_Magic, code = Stuff_NoCode)
static
__u8
*
StuffData
(
__u8
*
src
,
__u32
length
,
__u8
*
dst
,
__u8
**
code_ptr_ptr
)
static
__u8
*
StuffData
(
__u8
*
src
,
__u32
length
,
__u8
*
dst
,
__u8
**
code_ptr_ptr
)
{
{
__u8
*
end
=
src
+
length
;
__u8
*
end
=
src
+
length
;
__u8
*
code_ptr
=
*
code_ptr_ptr
;
__u8
*
code_ptr
=
*
code_ptr_ptr
;
__u8
code
=
Stuff_NoCode
,
count
=
0
;
__u8
code
=
Stuff_NoCode
,
count
=
0
;
if
(
!
length
)
if
(
!
length
)
return
(
dst
);
return
(
dst
);
if
(
code_ptr
)
if
(
code_ptr
)
{
{
/*
/*
* Recover state from last call, if applicable
* Recover state from last call, if applicable
*/
*/
...
@@ -640,23 +571,18 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
...
@@ -640,23 +571,18 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
count
=
(
*
code_ptr
^
Stuff_Magic
)
&
Stuff_CountMask
;
count
=
(
*
code_ptr
^
Stuff_Magic
)
&
Stuff_CountMask
;
}
}
while
(
src
<
end
)
while
(
src
<
end
)
{
{
switch
(
code
)
{
switch
(
code
)
{
/* Stuff_NoCode: If no current code, select one */
/* Stuff_NoCode: If no current code, select one */
case
Stuff_NoCode
:
case
Stuff_NoCode
:
/* Record where we're going to put this code */
/* Record where we're going to put this code */
code_ptr
=
dst
++
;
code_ptr
=
dst
++
;
count
=
0
;
/* Reset the count (zero means one instance) */
count
=
0
;
/* Reset the count (zero means one instance) */
/* Tentatively start a new block */
/* Tentatively start a new block */
if
(
*
src
==
0
)
if
(
*
src
==
0
)
{
{
code
=
Stuff_Zero
;
code
=
Stuff_Zero
;
src
++
;
src
++
;
}
}
else
{
else
{
code
=
Stuff_Same
;
code
=
Stuff_Same
;
*
dst
++
=
*
src
++
^
Stuff_Magic
;
*
dst
++
=
*
src
++
^
Stuff_Magic
;
}
}
...
@@ -668,13 +594,10 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
...
@@ -668,13 +594,10 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
/* Stuff_Zero: We already have at least one zero encoded */
/* Stuff_Zero: We already have at least one zero encoded */
case
Stuff_Zero
:
case
Stuff_Zero
:
/* If another zero, count it, else finish this code block */
/* If another zero, count it, else finish this code block */
if
(
*
src
==
0
)
if
(
*
src
==
0
)
{
{
count
++
;
count
++
;
src
++
;
src
++
;
}
}
else
{
else
{
StuffData_FinishBlock
(
Stuff_Zero
+
count
);
StuffData_FinishBlock
(
Stuff_Zero
+
count
);
}
}
break
;
break
;
...
@@ -682,16 +605,14 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
...
@@ -682,16 +605,14 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
/* Stuff_Same: We already have at least one byte encoded */
/* Stuff_Same: We already have at least one byte encoded */
case
Stuff_Same
:
case
Stuff_Same
:
/* If another one the same, count it */
/* If another one the same, count it */
if
((
*
src
^
Stuff_Magic
)
==
code_ptr
[
1
])
if
((
*
src
^
Stuff_Magic
)
==
code_ptr
[
1
])
{
{
count
++
;
count
++
;
src
++
;
src
++
;
break
;
break
;
}
}
/* else, this byte does not match this block. */
/* else, this byte does not match this block. */
/* If we already have two or more bytes encoded, finish this code block */
/* If we already have two or more bytes encoded, finish this code block */
if
(
count
)
if
(
count
)
{
{
StuffData_FinishBlock
(
Stuff_Same
+
count
);
StuffData_FinishBlock
(
Stuff_Same
+
count
);
break
;
break
;
}
}
...
@@ -710,50 +631,44 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
...
@@ -710,50 +631,44 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
/* Stuff_Diff: We have at least two *different* bytes encoded */
/* Stuff_Diff: We have at least two *different* bytes encoded */
case
Stuff_Diff
:
case
Stuff_Diff
:
/* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */
/* If this is a zero, must encode a Stuff_DiffZero, and begin a new block */
if
(
*
src
==
0
)
if
(
*
src
==
0
)
{
{
StuffData_FinishBlock
(
Stuff_DiffZero
+
StuffData_FinishBlock
(
Stuff_DiffZero
+
count
);
count
);
}
}
/* else, if we have three in a row, it is worth starting a Stuff_Same block */
/* else, if we have three in a row, it is worth starting a Stuff_Same block */
else
if
((
*
src
^
Stuff_Magic
)
==
dst
[
-
1
]
&&
dst
[
-
1
]
==
dst
[
-
2
])
else
if
((
*
src
^
Stuff_Magic
)
==
dst
[
-
1
]
{
&&
dst
[
-
1
]
==
dst
[
-
2
])
{
/* Back off the last two characters we encoded */
/* Back off the last two characters we encoded */
code
+=
count
-
2
;
code
+=
count
-
2
;
/* Note: "Stuff_Diff + 0" is an illegal code */
/* Note: "Stuff_Diff + 0" is an illegal code */
if
(
code
==
Stuff_Diff
+
0
)
if
(
code
==
Stuff_Diff
+
0
)
{
{
code
=
Stuff_Same
+
0
;
code
=
Stuff_Same
+
0
;
}
}
StuffData_FinishBlock
(
code
);
StuffData_FinishBlock
(
code
);
code_ptr
=
dst
-
2
;
code_ptr
=
dst
-
2
;
/* dst[-1] already holds the correct value */
/* dst[-1] already holds the correct value */
count
=
2
;
/* 2 means three bytes encoded */
count
=
2
;
/* 2 means three bytes encoded */
code
=
Stuff_Same
;
code
=
Stuff_Same
;
}
}
/* else, another different byte, so add it to the block */
/* else, another different byte, so add it to the block */
else
else
{
{
*
dst
++
=
*
src
^
Stuff_Magic
;
*
dst
++
=
*
src
^
Stuff_Magic
;
count
++
;
count
++
;
}
}
src
++
;
/* Consume the byte */
src
++
;
/* Consume the byte */
break
;
break
;
}
}
if
(
count
==
Stuff_MaxCount
)
if
(
count
==
Stuff_MaxCount
)
{
{
StuffData_FinishBlock
(
code
+
count
);
StuffData_FinishBlock
(
code
+
count
);
}
}
}
}
if
(
code
==
Stuff_NoCode
)
if
(
code
==
Stuff_NoCode
)
{
{
*
code_ptr_ptr
=
NULL
;
*
code_ptr_ptr
=
NULL
;
}
}
else
{
else
{
*
code_ptr_ptr
=
code_ptr
;
*
code_ptr_ptr
=
code_ptr
;
StuffData_FinishBlock
(
code
+
count
);
StuffData_FinishBlock
(
code
+
count
);
}
}
return
(
dst
);
return
(
dst
);
}
}
/*
/*
...
@@ -776,67 +691,64 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
...
@@ -776,67 +691,64 @@ static __u8 *StuffData(__u8 *src, __u32 length, __u8 *dst, __u8 **code_ptr_ptr)
* call to resume correctly).
* call to resume correctly).
*/
*/
static
__u8
*
UnStuffData
(
__u8
*
src
,
__u8
*
end
,
__u8
*
dst
,
__u32
dst_length
)
static
__u8
*
UnStuffData
(
__u8
*
src
,
__u8
*
end
,
__u8
*
dst
,
__u32
dst_length
)
{
{
__u8
*
dst_end
=
dst
+
dst_length
;
__u8
*
dst_end
=
dst
+
dst_length
;
/* Sanity check */
/* Sanity check */
if
(
!
src
||
!
end
||
!
dst
||
!
dst_length
)
if
(
!
src
||
!
end
||
!
dst
||
!
dst_length
)
return
(
NULL
);
return
(
NULL
);
while
(
src
<
end
&&
dst
<
dst_end
)
while
(
src
<
end
&&
dst
<
dst_end
)
{
{
int
count
=
(
*
src
^
Stuff_Magic
)
&
Stuff_CountMask
;
int
count
=
(
*
src
^
Stuff_Magic
)
&
Stuff_CountMask
;
switch
((
*
src
^
Stuff_Magic
)
&
Stuff_CodeMask
)
switch
((
*
src
^
Stuff_Magic
)
&
Stuff_CodeMask
)
{
{
case
Stuff_Diff
:
case
Stuff_Diff
:
if
(
src
+
1
+
count
>=
end
)
if
(
src
+
1
+
count
>=
end
)
return
(
NULL
);
return
(
NULL
);
do
do
{
{
*
dst
++
=
*++
src
^
Stuff_Magic
;
*
dst
++
=
*++
src
^
Stuff_Magic
;
}
}
while
(
--
count
>=
0
&&
dst
<
dst_end
);
while
(
--
count
>=
0
&&
dst
<
dst_end
);
if
(
count
<
0
)
if
(
count
<
0
)
src
+=
1
;
src
+=
1
;
else
else
{
{
if
(
count
==
0
)
if
(
count
==
0
)
*
src
=
Stuff_Same
^
Stuff_Magic
;
*
src
=
Stuff_Same
^
Stuff_Magic
;
else
else
*
src
=
(
Stuff_Diff
+
count
)
^
Stuff_Magic
;
*
src
=
(
Stuff_Diff
+
count
)
^
Stuff_Magic
;
}
}
break
;
break
;
case
Stuff_DiffZero
:
case
Stuff_DiffZero
:
if
(
src
+
1
+
count
>=
end
)
if
(
src
+
1
+
count
>=
end
)
return
(
NULL
);
return
(
NULL
);
do
do
{
{
*
dst
++
=
*++
src
^
Stuff_Magic
;
*
dst
++
=
*++
src
^
Stuff_Magic
;
}
}
while
(
--
count
>=
0
&&
dst
<
dst_end
);
while
(
--
count
>=
0
&&
dst
<
dst_end
);
if
(
count
<
0
)
if
(
count
<
0
)
*
src
=
Stuff_Zero
^
Stuff_Magic
;
*
src
=
Stuff_Zero
^
Stuff_Magic
;
else
else
*
src
=
(
Stuff_DiffZero
+
count
)
^
Stuff_Magic
;
*
src
=
(
Stuff_DiffZero
+
count
)
^
Stuff_Magic
;
break
;
break
;
case
Stuff_Same
:
case
Stuff_Same
:
if
(
src
+
1
>=
end
)
if
(
src
+
1
>=
end
)
return
(
NULL
);
return
(
NULL
);
do
do
{
{
*
dst
++
=
src
[
1
]
^
Stuff_Magic
;
*
dst
++
=
src
[
1
]
^
Stuff_Magic
;
}
}
while
(
--
count
>=
0
&&
dst
<
dst_end
);
while
(
--
count
>=
0
&&
dst
<
dst_end
);
if
(
count
<
0
)
if
(
count
<
0
)
src
+=
2
;
src
+=
2
;
else
else
*
src
=
(
Stuff_Same
+
count
)
^
Stuff_Magic
;
*
src
=
(
Stuff_Same
+
count
)
^
Stuff_Magic
;
break
;
break
;
case
Stuff_Zero
:
case
Stuff_Zero
:
do
do
{
{
*
dst
++
=
0
;
*
dst
++
=
0
;
}
}
while
(
--
count
>=
0
&&
dst
<
dst_end
);
while
(
--
count
>=
0
&&
dst
<
dst_end
);
if
(
count
<
0
)
if
(
count
<
0
)
src
+=
1
;
src
+=
1
;
else
else
...
@@ -845,9 +757,9 @@ static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length)
...
@@ -845,9 +757,9 @@ static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length)
}
}
}
}
if
(
dst
<
dst_end
)
if
(
dst
<
dst_end
)
return
(
NULL
);
return
(
NULL
);
else
else
return
(
src
);
return
(
src
);
}
}
...
@@ -862,16 +774,19 @@ static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length)
...
@@ -862,16 +774,19 @@ static __u8 *UnStuffData(__u8 *src, __u8 *end, __u8 *dst, __u32 dst_length)
* currently in effect (57.6 or 115.2) is returned.
* currently in effect (57.6 or 115.2) is returned.
*/
*/
static
unsigned
int
get_baud
(
struct
tty_struct
*
tty
)
static
unsigned
int
get_baud
(
struct
tty_struct
*
tty
)
{
{
if
(
!
tty
||
!
tty
->
termios
)
return
(
0
);
if
(
!
tty
||
!
tty
->
termios
)
if
((
tty
->
termios
->
c_cflag
&
CBAUD
)
==
B38400
&&
tty
->
driver_data
)
return
(
0
);
{
if
((
tty
->
termios
->
c_cflag
&
CBAUD
)
==
B38400
&&
tty
->
driver_data
)
{
struct
async_struct
*
info
=
(
struct
async_struct
*
)
tty
->
driver_data
;
struct
async_struct
*
info
=
if
((
info
->
flags
&
ASYNC_SPD_MASK
)
==
ASYNC_SPD_HI
)
return
(
B57600
);
(
struct
async_struct
*
)
tty
->
driver_data
;
if
((
info
->
flags
&
ASYNC_SPD_MASK
)
==
ASYNC_SPD_VHI
)
return
(
B115200
);
if
((
info
->
flags
&
ASYNC_SPD_MASK
)
==
ASYNC_SPD_HI
)
}
return
(
B57600
);
return
(
tty
->
termios
->
c_cflag
&
CBAUD
);
if
((
info
->
flags
&
ASYNC_SPD_MASK
)
==
ASYNC_SPD_VHI
)
}
return
(
B115200
);
}
return
(
tty
->
termios
->
c_cflag
&
CBAUD
);
}
/*
/*
* set_baud sets the baud rate to the rate defined by baudcode
* set_baud sets the baud rate to the rate defined by baudcode
...
@@ -882,12 +797,12 @@ static unsigned int get_baud(struct tty_struct *tty)
...
@@ -882,12 +797,12 @@ static unsigned int get_baud(struct tty_struct *tty)
* user, so it is simplest to just avoid using 38400.
* user, so it is simplest to just avoid using 38400.
*/
*/
static
void
set_baud
(
struct
tty_struct
*
tty
,
unsigned
int
baudcode
)
static
void
set_baud
(
struct
tty_struct
*
tty
,
unsigned
int
baudcode
)
{
{
struct
termios
old_termios
=
*
(
tty
->
termios
);
struct
termios
old_termios
=
*
(
tty
->
termios
);
tty
->
termios
->
c_cflag
&=
~
CBAUD
;
/* Clear the old baud setting */
tty
->
termios
->
c_cflag
&=
~
CBAUD
;
/* Clear the old baud setting */
tty
->
termios
->
c_cflag
|=
baudcode
;
/* Set the new baud setting */
tty
->
termios
->
c_cflag
|=
baudcode
;
/* Set the new baud setting */
tty
->
driver
.
set_termios
(
tty
,
&
old_termios
);
tty
->
driver
.
set_termios
(
tty
,
&
old_termios
);
}
}
/*
/*
* Convert a string to a Metricom Address.
* Convert a string to a Metricom Address.
...
@@ -898,26 +813,29 @@ static void set_baud(struct tty_struct *tty, unsigned int baudcode)
...
@@ -898,26 +813,29 @@ static void set_baud(struct tty_struct *tty, unsigned int baudcode)
(p)[4] == '-' && \
(p)[4] == '-' && \
isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) )
isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) )
static
int
string_to_radio_address
(
MetricomAddress
*
addr
,
__u8
*
p
)
static
int
string_to_radio_address
(
MetricomAddress
*
addr
,
__u8
*
p
)
{
{
if
(
!
IS_RADIO_ADDRESS
(
p
))
return
(
1
);
if
(
!
IS_RADIO_ADDRESS
(
p
))
return
(
1
);
addr
->
c
[
0
]
=
0
;
addr
->
c
[
0
]
=
0
;
addr
->
c
[
1
]
=
0
;
addr
->
c
[
1
]
=
0
;
addr
->
c
[
2
]
=
READHEX
(
p
[
0
])
<<
4
|
READHEX
(
p
[
1
]);
addr
->
c
[
2
]
=
READHEX
(
p
[
0
])
<<
4
|
READHEX
(
p
[
1
]);
addr
->
c
[
3
]
=
READHEX
(
p
[
2
])
<<
4
|
READHEX
(
p
[
3
]);
addr
->
c
[
3
]
=
READHEX
(
p
[
2
])
<<
4
|
READHEX
(
p
[
3
]);
addr
->
c
[
4
]
=
READHEX
(
p
[
5
])
<<
4
|
READHEX
(
p
[
6
]);
addr
->
c
[
4
]
=
READHEX
(
p
[
5
])
<<
4
|
READHEX
(
p
[
6
]);
addr
->
c
[
5
]
=
READHEX
(
p
[
7
])
<<
4
|
READHEX
(
p
[
8
]);
addr
->
c
[
5
]
=
READHEX
(
p
[
7
])
<<
4
|
READHEX
(
p
[
8
]);
return
(
0
);
return
(
0
);
}
}
/*
/*
* Convert a Metricom Address to a string.
* Convert a Metricom Address to a string.
*/
*/
static
__u8
*
radio_address_to_string
(
const
MetricomAddress
*
addr
,
MetricomAddressString
*
p
)
static
__u8
*
radio_address_to_string
(
const
MetricomAddress
*
addr
,
MetricomAddressString
*
p
)
{
{
sprintf
(
p
->
c
,
"%02X%02X-%02X%02X"
,
addr
->
c
[
2
],
addr
->
c
[
3
],
addr
->
c
[
4
],
addr
->
c
[
5
]);
sprintf
(
p
->
c
,
"%02X%02X-%02X%02X"
,
addr
->
c
[
2
],
addr
->
c
[
3
],
return
(
p
->
c
);
addr
->
c
[
4
],
addr
->
c
[
5
]);
return
(
p
->
c
);
}
}
/*
/*
...
@@ -934,26 +852,30 @@ static int allocate_buffers(struct strip *strip_info)
...
@@ -934,26 +852,30 @@ static int allocate_buffers(struct strip *strip_info)
__u8
*
r
=
kmalloc
(
MAX_RECV_MTU
,
GFP_ATOMIC
);
__u8
*
r
=
kmalloc
(
MAX_RECV_MTU
,
GFP_ATOMIC
);
__u8
*
s
=
kmalloc
(
sx_size
,
GFP_ATOMIC
);
__u8
*
s
=
kmalloc
(
sx_size
,
GFP_ATOMIC
);
__u8
*
t
=
kmalloc
(
tx_size
,
GFP_ATOMIC
);
__u8
*
t
=
kmalloc
(
tx_size
,
GFP_ATOMIC
);
if
(
r
&&
s
&&
t
)
if
(
r
&&
s
&&
t
)
{
{
strip_info
->
rx_buff
=
r
;
strip_info
->
rx_buff
=
r
;
strip_info
->
sx_buff
=
s
;
strip_info
->
sx_buff
=
s
;
strip_info
->
tx_buff
=
t
;
strip_info
->
tx_buff
=
t
;
strip_info
->
sx_size
=
sx_size
;
strip_info
->
sx_size
=
sx_size
;
strip_info
->
tx_size
=
tx_size
;
strip_info
->
tx_size
=
tx_size
;
strip_info
->
mtu
=
dev
->
mtu
;
strip_info
->
mtu
=
dev
->
mtu
;
return
(
1
);
return
(
1
);
}
}
if
(
r
)
kfree
(
r
);
if
(
r
)
if
(
s
)
kfree
(
s
);
kfree
(
r
);
if
(
t
)
kfree
(
t
);
if
(
s
)
return
(
0
);
kfree
(
s
);
if
(
t
)
kfree
(
t
);
return
(
0
);
}
}
/*
/*
* MTU has been changed by the IP layer. Unfortunately we are not told
* MTU has been changed by the IP layer. Unfortunately we are not told
* about this, but we spot it ourselves and fix things up. We could be in
* about this, but we spot it ourselves and fix things up. We could be in
* an upcall from the tty driver, or in an ip packet queue.
* an upcall from the tty driver, or in an ip packet queue.
*
* Caller must hold the strip_lock
*/
*/
static
void
strip_changedmtu
(
struct
strip
*
strip_info
)
static
void
strip_changedmtu
(
struct
strip
*
strip_info
)
...
@@ -963,65 +885,52 @@ static void strip_changedmtu(struct strip *strip_info)
...
@@ -963,65 +885,52 @@ static void strip_changedmtu(struct strip *strip_info)
unsigned
char
*
orbuff
=
strip_info
->
rx_buff
;
unsigned
char
*
orbuff
=
strip_info
->
rx_buff
;
unsigned
char
*
osbuff
=
strip_info
->
sx_buff
;
unsigned
char
*
osbuff
=
strip_info
->
sx_buff
;
unsigned
char
*
otbuff
=
strip_info
->
tx_buff
;
unsigned
char
*
otbuff
=
strip_info
->
tx_buff
;
InterruptStatus
intstat
;
if
(
dev
->
mtu
>
MAX_SEND_MTU
)
if
(
dev
->
mtu
>
MAX_SEND_MTU
)
{
{
printk
(
KERN_ERR
printk
(
KERN_ERR
"%s: MTU exceeds maximum allowable (%d), MTU change cancelled.
\n
"
,
"%s: MTU exceeds maximum allowable (%d), MTU change cancelled.
\n
"
,
strip_info
->
dev
.
name
,
MAX_SEND_MTU
);
strip_info
->
dev
.
name
,
MAX_SEND_MTU
);
dev
->
mtu
=
old_mtu
;
dev
->
mtu
=
old_mtu
;
return
;
return
;
}
}
/*
if
(
!
allocate_buffers
(
strip_info
))
{
* Have to disable interrupts here because we're reallocating and resizing
* the serial buffers, and we can't have data arriving in them while we're
* moving them around in memory. This may cause data to be lost on the serial
* port, but hopefully people won't change MTU that often.
* Also note, this may not work on a symmetric multi-processor system.
*/
intstat
=
DisableInterrupts
();
if
(
!
allocate_buffers
(
strip_info
))
{
RestoreInterrupts
(
intstat
);
printk
(
KERN_ERR
"%s: unable to grow strip buffers, MTU change cancelled.
\n
"
,
printk
(
KERN_ERR
"%s: unable to grow strip buffers, MTU change cancelled.
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
dev
->
mtu
=
old_mtu
;
dev
->
mtu
=
old_mtu
;
return
;
return
;
}
}
if
(
strip_info
->
sx_count
)
if
(
strip_info
->
sx_count
)
{
{
if
(
strip_info
->
sx_count
<=
strip_info
->
sx_size
)
if
(
strip_info
->
sx_count
<=
strip_info
->
sx_size
)
memcpy
(
strip_info
->
sx_buff
,
osbuff
,
strip_info
->
sx_count
);
memcpy
(
strip_info
->
sx_buff
,
osbuff
,
else
strip_info
->
sx_count
);
{
else
{
strip_info
->
discard
=
strip_info
->
sx_count
;
strip_info
->
discard
=
strip_info
->
sx_count
;
strip_info
->
rx_over_errors
++
;
strip_info
->
rx_over_errors
++
;
}
}
}
}
if
(
strip_info
->
tx_left
)
if
(
strip_info
->
tx_left
)
{
{
if
(
strip_info
->
tx_left
<=
strip_info
->
tx_size
)
if
(
strip_info
->
tx_left
<=
strip_info
->
tx_size
)
memcpy
(
strip_info
->
tx_buff
,
strip_info
->
tx_head
,
strip_info
->
tx_left
);
memcpy
(
strip_info
->
tx_buff
,
strip_info
->
tx_head
,
else
strip_info
->
tx_left
);
{
else
{
strip_info
->
tx_left
=
0
;
strip_info
->
tx_left
=
0
;
strip_info
->
tx_dropped
++
;
strip_info
->
tx_dropped
++
;
}
}
}
}
strip_info
->
tx_head
=
strip_info
->
tx_buff
;
strip_info
->
tx_head
=
strip_info
->
tx_buff
;
RestoreInterrupts
(
intstat
);
printk
(
KERN_NOTICE
"%s: strip MTU changed fom %d to %d.
\n
"
,
printk
(
KERN_NOTICE
"%s: strip MTU changed fom %d to %d.
\n
"
,
strip_info
->
dev
.
name
,
old_mtu
,
strip_info
->
mtu
);
strip_info
->
dev
.
name
,
old_mtu
,
strip_info
->
mtu
);
if
(
orbuff
)
kfree
(
orbuff
);
if
(
orbuff
)
if
(
osbuff
)
kfree
(
osbuff
);
kfree
(
orbuff
);
if
(
otbuff
)
kfree
(
otbuff
);
if
(
osbuff
)
kfree
(
osbuff
);
if
(
otbuff
)
kfree
(
otbuff
);
}
}
static
void
strip_unlock
(
struct
strip
*
strip_info
)
static
void
strip_unlock
(
struct
strip
*
strip_info
)
...
@@ -1029,7 +938,7 @@ static void strip_unlock(struct strip *strip_info)
...
@@ -1029,7 +938,7 @@ static void strip_unlock(struct strip *strip_info)
/*
/*
* Set the timer to go off in one second.
* Set the timer to go off in one second.
*/
*/
strip_info
->
idle_timer
.
expires
=
jiffies
+
1
*
HZ
;
strip_info
->
idle_timer
.
expires
=
jiffies
+
1
*
HZ
;
add_timer
(
&
strip_info
->
idle_timer
);
add_timer
(
&
strip_info
->
idle_timer
);
netif_wake_queue
(
&
strip_info
->
dev
);
netif_wake_queue
(
&
strip_info
->
dev
);
}
}
...
@@ -1059,8 +968,7 @@ shift_buffer(char *buffer, int requested_offset, int requested_len,
...
@@ -1059,8 +968,7 @@ shift_buffer(char *buffer, int requested_offset, int requested_len,
if
(
*
total
+
printed
<=
requested_offset
)
{
if
(
*
total
+
printed
<=
requested_offset
)
{
*
total
+=
printed
;
*
total
+=
printed
;
*
buf
=
buffer
;
*
buf
=
buffer
;
}
}
else
{
else
{
if
(
*
total
<
requested_offset
)
{
if
(
*
total
<
requested_offset
)
{
*
slop
=
requested_offset
-
*
total
;
*
slop
=
requested_offset
-
*
total
;
}
}
...
@@ -1068,8 +976,7 @@ shift_buffer(char *buffer, int requested_offset, int requested_len,
...
@@ -1068,8 +976,7 @@ shift_buffer(char *buffer, int requested_offset, int requested_len,
}
}
if
(
*
total
>
requested_offset
+
requested_len
)
{
if
(
*
total
>
requested_offset
+
requested_len
)
{
return
1
;
return
1
;
}
}
else
{
else
{
return
0
;
return
0
;
}
}
}
}
...
@@ -1117,32 +1024,37 @@ calc_start_len(char *buffer, char **start, int requested_offset,
...
@@ -1117,32 +1024,37 @@ calc_start_len(char *buffer, char **start, int requested_offset,
static
char
*
time_delta
(
char
buffer
[],
long
time
)
static
char
*
time_delta
(
char
buffer
[],
long
time
)
{
{
time
-=
jiffies
;
time
-=
jiffies
;
if
(
time
>
LongTime
/
2
)
return
(
"Not scheduled"
);
if
(
time
>
LongTime
/
2
)
if
(
time
<
0
)
time
=
0
;
/* Don't print negative times */
return
(
"Not scheduled"
);
if
(
time
<
0
)
time
=
0
;
/* Don't print negative times */
sprintf
(
buffer
,
"%ld seconds"
,
time
/
HZ
);
sprintf
(
buffer
,
"%ld seconds"
,
time
/
HZ
);
return
(
buffer
);
return
(
buffer
);
}
}
static
int
sprintf_neighbours
(
char
*
buffer
,
MetricomNodeTable
*
table
,
char
*
title
)
static
int
sprintf_neighbours
(
char
*
buffer
,
MetricomNodeTable
*
table
,
char
*
title
)
{
{
/* We wrap this in a do/while loop, so if the table changes */
/* We wrap this in a do/while loop, so if the table changes */
/* while we're reading it, we just go around and try again. */
/* while we're reading it, we just go around and try again. */
struct
timeval
t
;
struct
timeval
t
;
char
*
ptr
;
char
*
ptr
;
do
unsigned
long
flags
;
{
do
{
int
i
;
int
i
;
t
=
table
->
timestamp
;
t
=
table
->
timestamp
;
ptr
=
buffer
;
ptr
=
buffer
;
if
(
table
->
num_nodes
)
ptr
+=
sprintf
(
ptr
,
"
\n
%s
\n
"
,
title
);
if
(
table
->
num_nodes
)
for
(
i
=
0
;
i
<
table
->
num_nodes
;
i
++
)
ptr
+=
sprintf
(
ptr
,
"
\n
%s
\n
"
,
title
);
{
for
(
i
=
0
;
i
<
table
->
num_nodes
;
i
++
)
{
InterruptStatus
intstat
=
DisableInterrupts
(
);
spin_lock_irqsave
(
&
strip_lock
,
flags
);
MetricomNode
node
=
table
->
node
[
i
];
MetricomNode
node
=
table
->
node
[
i
];
RestoreInterrupts
(
intstat
);
spin_unlock_irqrestore
(
&
strip_lock
,
flags
);
ptr
+=
sprintf
(
ptr
,
" %s
\n
"
,
node
.
c
);
ptr
+=
sprintf
(
ptr
,
" %s
\n
"
,
node
.
c
);
}
}
}
while
(
table
->
timestamp
.
tv_sec
!=
t
.
tv_sec
||
table
->
timestamp
.
tv_usec
!=
t
.
tv_usec
);
}
while
(
table
->
timestamp
.
tv_sec
!=
t
.
tv_sec
||
table
->
timestamp
.
tv_usec
!=
t
.
tv_usec
);
return
ptr
-
buffer
;
return
ptr
-
buffer
;
}
}
...
@@ -1152,8 +1064,7 @@ static int sprintf_neighbours(char *buffer, MetricomNodeTable *table, char *titl
...
@@ -1152,8 +1064,7 @@ static int sprintf_neighbours(char *buffer, MetricomNodeTable *table, char *titl
* than 4K of data into it. With the maximum of 32 portables and 32 poletops
* than 4K of data into it. With the maximum of 32 portables and 32 poletops
* reported, the routine outputs 3107 bytes into the buffer.
* reported, the routine outputs 3107 bytes into the buffer.
*/
*/
static
int
static
int
sprintf_status_info
(
char
*
buffer
,
struct
strip
*
strip_info
)
sprintf_status_info
(
char
*
buffer
,
struct
strip
*
strip_info
)
{
{
char
temp
[
32
];
char
temp
[
32
];
char
*
p
=
buffer
;
char
*
p
=
buffer
;
...
@@ -1161,7 +1072,6 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
...
@@ -1161,7 +1072,6 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
/* First, we must copy all of our data to a safe place, */
/* First, we must copy all of our data to a safe place, */
/* in case a serial interrupt comes in and changes it. */
/* in case a serial interrupt comes in and changes it. */
InterruptStatus
intstat
=
DisableInterrupts
();
int
tx_left
=
strip_info
->
tx_left
;
int
tx_left
=
strip_info
->
tx_left
;
unsigned
long
rx_average_pps
=
strip_info
->
rx_average_pps
;
unsigned
long
rx_average_pps
=
strip_info
->
rx_average_pps
;
unsigned
long
tx_average_pps
=
strip_info
->
tx_average_pps
;
unsigned
long
tx_average_pps
=
strip_info
->
tx_average_pps
;
...
@@ -1175,9 +1085,10 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
...
@@ -1175,9 +1085,10 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
FirmwareVersion
firmware_version
=
strip_info
->
firmware_version
;
FirmwareVersion
firmware_version
=
strip_info
->
firmware_version
;
SerialNumber
serial_number
=
strip_info
->
serial_number
;
SerialNumber
serial_number
=
strip_info
->
serial_number
;
BatteryVoltage
battery_voltage
=
strip_info
->
battery_voltage
;
BatteryVoltage
battery_voltage
=
strip_info
->
battery_voltage
;
char
*
if_name
=
strip_info
->
dev
.
name
;
char
*
if_name
=
strip_info
->
dev
.
name
;
MetricomAddress
true_dev_addr
=
strip_info
->
true_dev_addr
;
MetricomAddress
true_dev_addr
=
strip_info
->
true_dev_addr
;
MetricomAddress
dev_dev_addr
=
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
;
MetricomAddress
dev_dev_addr
=
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
;
int
manual_dev_addr
=
strip_info
->
manual_dev_addr
;
int
manual_dev_addr
=
strip_info
->
manual_dev_addr
;
#ifdef EXT_COUNTERS
#ifdef EXT_COUNTERS
unsigned
long
rx_bytes
=
strip_info
->
rx_bytes
;
unsigned
long
rx_bytes
=
strip_info
->
rx_bytes
;
...
@@ -1189,51 +1100,66 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
...
@@ -1189,51 +1100,66 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
unsigned
long
rx_ebytes
=
strip_info
->
rx_ebytes
;
unsigned
long
rx_ebytes
=
strip_info
->
rx_ebytes
;
unsigned
long
tx_ebytes
=
strip_info
->
tx_ebytes
;
unsigned
long
tx_ebytes
=
strip_info
->
tx_ebytes
;
#endif
#endif
RestoreInterrupts
(
intstat
);
p
+=
sprintf
(
p
,
"
\n
Interface name
\t\t
%s
\n
"
,
if_name
);
p
+=
sprintf
(
p
,
"
\n
Interface name
\t\t
%s
\n
"
,
if_name
);
p
+=
sprintf
(
p
,
" Radio working:
\t\t
%s
\n
"
,
working
?
"Yes"
:
"No"
);
p
+=
sprintf
(
p
,
" Radio working:
\t\t
%s
\n
"
,
working
?
"Yes"
:
"No"
);
radio_address_to_string
(
&
true_dev_addr
,
&
addr_string
);
radio_address_to_string
(
&
true_dev_addr
,
&
addr_string
);
p
+=
sprintf
(
p
,
" Radio address:
\t\t
%s
\n
"
,
addr_string
.
c
);
p
+=
sprintf
(
p
,
" Radio address:
\t\t
%s
\n
"
,
addr_string
.
c
);
if
(
manual_dev_addr
)
if
(
manual_dev_addr
)
{
{
radio_address_to_string
(
&
dev_dev_addr
,
&
addr_string
);
radio_address_to_string
(
&
dev_dev_addr
,
&
addr_string
);
p
+=
sprintf
(
p
,
" Device address:
\t
%s
\n
"
,
addr_string
.
c
);
p
+=
sprintf
(
p
,
" Device address:
\t
%s
\n
"
,
addr_string
.
c
);
}
}
p
+=
sprintf
(
p
,
" Firmware version:
\t
%s"
,
!
working
?
"Unknown"
:
p
+=
sprintf
(
p
,
" Firmware version:
\t
%s"
,
!
working
?
"Unknown"
:
!
firmware_level
?
"Should be upgraded"
:
!
firmware_level
?
"Should be upgraded"
:
firmware_version
.
c
);
firmware_version
.
c
);
if
(
firmware_level
>=
ChecksummedMessages
)
p
+=
sprintf
(
p
,
" (Checksums Enabled)"
);
if
(
firmware_level
>=
ChecksummedMessages
)
p
+=
sprintf
(
p
,
" (Checksums Enabled)"
);
p
+=
sprintf
(
p
,
"
\n
"
);
p
+=
sprintf
(
p
,
"
\n
"
);
p
+=
sprintf
(
p
,
" Serial number:
\t\t
%s
\n
"
,
serial_number
.
c
);
p
+=
sprintf
(
p
,
" Serial number:
\t\t
%s
\n
"
,
serial_number
.
c
);
p
+=
sprintf
(
p
,
" Battery voltage:
\t
%s
\n
"
,
battery_voltage
.
c
);
p
+=
sprintf
(
p
,
" Battery voltage:
\t
%s
\n
"
,
battery_voltage
.
c
);
p
+=
sprintf
(
p
,
" Transmit queue (bytes):%d
\n
"
,
tx_left
);
p
+=
sprintf
(
p
,
" Transmit queue (bytes):%d
\n
"
,
tx_left
);
p
+=
sprintf
(
p
,
" Receive packet rate: %ld packets per second
\n
"
,
rx_average_pps
/
8
);
p
+=
sprintf
(
p
,
" Receive packet rate: %ld packets per second
\n
"
,
p
+=
sprintf
(
p
,
" Transmit packet rate: %ld packets per second
\n
"
,
tx_average_pps
/
8
);
rx_average_pps
/
8
);
p
+=
sprintf
(
p
,
" Sent packet rate: %ld packets per second
\n
"
,
sx_average_pps
/
8
);
p
+=
sprintf
(
p
,
" Transmit packet rate: %ld packets per second
\n
"
,
p
+=
sprintf
(
p
,
" Next watchdog probe:
\t
%s
\n
"
,
time_delta
(
temp
,
watchdog_doprobe
));
tx_average_pps
/
8
);
p
+=
sprintf
(
p
,
" Next watchdog reset:
\t
%s
\n
"
,
time_delta
(
temp
,
watchdog_doreset
));
p
+=
sprintf
(
p
,
" Sent packet rate: %ld packets per second
\n
"
,
sx_average_pps
/
8
);
p
+=
sprintf
(
p
,
" Next watchdog probe:
\t
%s
\n
"
,
time_delta
(
temp
,
watchdog_doprobe
));
p
+=
sprintf
(
p
,
" Next watchdog reset:
\t
%s
\n
"
,
time_delta
(
temp
,
watchdog_doreset
));
p
+=
sprintf
(
p
,
" Next gratuitous ARP:
\t
"
);
p
+=
sprintf
(
p
,
" Next gratuitous ARP:
\t
"
);
if
(
!
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
)))
if
(
!
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
)))
p
+=
sprintf
(
p
,
"Disabled
\n
"
);
p
+=
sprintf
(
p
,
"Disabled
\n
"
);
else
else
{
{
p
+=
sprintf
(
p
,
"%s
\n
"
,
time_delta
(
temp
,
gratuitous_arp
));
p
+=
sprintf
(
p
,
"%s
\n
"
,
time_delta
(
temp
,
gratuitous_arp
));
p
+=
sprintf
(
p
,
" Next ARP interval:
\t
%ld seconds
\n
"
,
JIFFIE_TO_SEC
(
arp_interval
));
p
+=
sprintf
(
p
,
" Next ARP interval:
\t
%ld seconds
\n
"
,
JIFFIE_TO_SEC
(
arp_interval
));
}
}
if
(
working
)
if
(
working
)
{
{
#ifdef EXT_COUNTERS
#ifdef EXT_COUNTERS
p
+=
sprintf
(
p
,
"
\n
"
);
p
+=
sprintf
(
p
,
"
\n
"
);
p
+=
sprintf
(
p
,
" Total bytes:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_bytes
,
tx_bytes
);
p
+=
sprintf
(
p
,
p
+=
sprintf
(
p
,
" thru radio:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_rbytes
,
tx_rbytes
);
" Total bytes:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
p
+=
sprintf
(
p
,
" thru serial port:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_sbytes
,
tx_sbytes
);
rx_bytes
,
tx_bytes
);
p
+=
sprintf
(
p
,
" Total stat/err bytes:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_ebytes
,
tx_ebytes
);
p
+=
sprintf
(
p
,
" thru radio:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_rbytes
,
tx_rbytes
);
p
+=
sprintf
(
p
,
" thru serial port:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_sbytes
,
tx_sbytes
);
p
+=
sprintf
(
p
,
" Total stat/err bytes:
\t
rx:
\t
%lu
\t
tx:
\t
%lu
\n
"
,
rx_ebytes
,
tx_ebytes
);
#endif
#endif
p
+=
sprintf_neighbours
(
p
,
&
strip_info
->
poletops
,
"Poletops:"
);
p
+=
sprintf_neighbours
(
p
,
&
strip_info
->
poletops
,
p
+=
sprintf_neighbours
(
p
,
&
strip_info
->
portables
,
"Portables:"
);
"Poletops:"
);
p
+=
sprintf_neighbours
(
p
,
&
strip_info
->
portables
,
"Portables:"
);
}
}
return
p
-
buffer
;
return
p
-
buffer
;
...
@@ -1244,23 +1170,27 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
...
@@ -1244,23 +1170,27 @@ sprintf_status_info(char *buffer, struct strip *strip_info)
* the /proc file system.
* the /proc file system.
*/
*/
static
int
get_status_info
(
char
*
buffer
,
char
**
start
,
off_t
req_offset
,
int
req_len
)
static
int
get_status_info
(
char
*
buffer
,
char
**
start
,
off_t
req_offset
,
int
req_len
)
{
{
int
total
=
0
,
slop
=
0
;
int
total
=
0
,
slop
=
0
;
struct
strip
*
strip_info
=
struct_strip_list
;
struct
strip
*
strip_info
=
struct_strip_list
;
char
*
buf
=
buffer
;
char
*
buf
=
buffer
;
buf
+=
sprintf
(
buf
,
"strip_version: %s
\n
"
,
StripVersion
);
buf
+=
sprintf
(
buf
,
"strip_version: %s
\n
"
,
StripVersion
);
if
(
shift_buffer
(
buffer
,
req_offset
,
req_len
,
&
total
,
&
slop
,
&
buf
))
goto
exit
;
if
(
shift_buffer
(
buffer
,
req_offset
,
req_len
,
&
total
,
&
slop
,
&
buf
))
goto
exit
;
while
(
strip_info
!=
NULL
)
while
(
strip_info
!=
NULL
)
{
{
buf
+=
sprintf_status_info
(
buf
,
strip_info
);
buf
+=
sprintf_status_info
(
buf
,
strip_info
);
if
(
shift_buffer
(
buffer
,
req_offset
,
req_len
,
&
total
,
&
slop
,
&
buf
))
break
;
if
(
shift_buffer
(
buffer
,
req_offset
,
req_len
,
&
total
,
&
slop
,
&
buf
))
break
;
strip_info
=
strip_info
->
next
;
strip_info
=
strip_info
->
next
;
}
}
exit:
exit:
return
(
calc_start_len
(
buffer
,
start
,
req_offset
,
req_len
,
total
,
buf
));
return
(
calc_start_len
(
buffer
,
start
,
req_offset
,
req_len
,
total
,
buf
));
}
}
/************************************************************************/
/************************************************************************/
...
@@ -1270,15 +1200,15 @@ static void ResetRadio(struct strip *strip_info)
...
@@ -1270,15 +1200,15 @@ static void ResetRadio(struct strip *strip_info)
{
{
struct
tty_struct
*
tty
=
strip_info
->
tty
;
struct
tty_struct
*
tty
=
strip_info
->
tty
;
static
const
char
init
[]
=
"ate0q1dt**starmode
\r
**"
;
static
const
char
init
[]
=
"ate0q1dt**starmode
\r
**"
;
StringDescriptor
s
=
{
init
,
sizeof
(
init
)
-
1
};
StringDescriptor
s
=
{
init
,
sizeof
(
init
)
-
1
};
/*
/*
* If the radio isn't working anymore,
* If the radio isn't working anymore,
* we should clear the old status information.
* we should clear the old status information.
*/
*/
if
(
strip_info
->
working
)
if
(
strip_info
->
working
)
{
{
printk
(
KERN_INFO
"%s: No response: Resetting radio.
\n
"
,
printk
(
KERN_INFO
"%s: No response: Resetting radio.
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
strip_info
->
firmware_version
.
c
[
0
]
=
'\0'
;
strip_info
->
firmware_version
.
c
[
0
]
=
'\0'
;
strip_info
->
serial_number
.
c
[
0
]
=
'\0'
;
strip_info
->
serial_number
.
c
[
0
]
=
'\0'
;
strip_info
->
battery_voltage
.
c
[
0
]
=
'\0'
;
strip_info
->
battery_voltage
.
c
[
0
]
=
'\0'
;
...
@@ -1297,9 +1227,10 @@ static void ResetRadio(struct strip *strip_info)
...
@@ -1297,9 +1227,10 @@ static void ResetRadio(struct strip *strip_info)
strip_info
->
sx_average_pps
=
0
;
strip_info
->
sx_average_pps
=
0
;
/* Mark radio address as unknown */
/* Mark radio address as unknown */
*
(
MetricomAddress
*
)
&
strip_info
->
true_dev_addr
=
zero_address
;
*
(
MetricomAddress
*
)
&
strip_info
->
true_dev_addr
=
zero_address
;
if
(
!
strip_info
->
manual_dev_addr
)
if
(
!
strip_info
->
manual_dev_addr
)
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
zero_address
;
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
zero_address
;
strip_info
->
working
=
FALSE
;
strip_info
->
working
=
FALSE
;
strip_info
->
firmware_level
=
NoStructure
;
strip_info
->
firmware_level
=
NoStructure
;
strip_info
->
next_command
=
CompatibilityCommand
;
strip_info
->
next_command
=
CompatibilityCommand
;
...
@@ -1307,8 +1238,7 @@ static void ResetRadio(struct strip *strip_info)
...
@@ -1307,8 +1238,7 @@ static void ResetRadio(struct strip *strip_info)
strip_info
->
watchdog_doreset
=
jiffies
+
1
*
HZ
;
strip_info
->
watchdog_doreset
=
jiffies
+
1
*
HZ
;
/* If the user has selected a baud rate above 38.4 see what magic we have to do */
/* If the user has selected a baud rate above 38.4 see what magic we have to do */
if
(
strip_info
->
user_baud
>
B38400
)
if
(
strip_info
->
user_baud
>
B38400
)
{
{
/*
/*
* Subtle stuff: Pay attention :-)
* Subtle stuff: Pay attention :-)
* If the serial port is currently at the user's selected (>38.4) rate,
* If the serial port is currently at the user's selected (>38.4) rate,
...
@@ -1318,18 +1248,22 @@ static void ResetRadio(struct strip *strip_info)
...
@@ -1318,18 +1248,22 @@ static void ResetRadio(struct strip *strip_info)
* issued the ATS304 command last time through, so this time we restore
* issued the ATS304 command last time through, so this time we restore
* the user's selected rate and issue the normal starmode reset string.
* the user's selected rate and issue the normal starmode reset string.
*/
*/
if
(
strip_info
->
user_baud
==
get_baud
(
tty
))
if
(
strip_info
->
user_baud
==
get_baud
(
tty
))
{
{
static
const
char
b0
[]
=
"ate0q1s304=57600
\r
"
;
static
const
char
b0
[]
=
"ate0q1s304=57600
\r
"
;
static
const
char
b1
[]
=
"ate0q1s304=115200
\r
"
;
static
const
char
b1
[]
=
"ate0q1s304=115200
\r
"
;
static
const
StringDescriptor
baudstring
[
2
]
=
static
const
StringDescriptor
baudstring
[
2
]
=
{
{
b0
,
sizeof
(
b0
)
-
1
},
{
b1
,
sizeof
(
b1
)
-
1
}
};
{
{
b0
,
sizeof
(
b0
)
-
1
}
,
{
b1
,
sizeof
(
b1
)
-
1
}
};
set_baud
(
tty
,
B19200
);
set_baud
(
tty
,
B19200
);
if
(
strip_info
->
user_baud
==
B57600
)
s
=
baudstring
[
0
];
if
(
strip_info
->
user_baud
==
B57600
)
else
if
(
strip_info
->
user_baud
==
B115200
)
s
=
baudstring
[
1
];
s
=
baudstring
[
0
];
else
s
=
baudstring
[
1
];
/* For now */
else
if
(
strip_info
->
user_baud
==
B115200
)
}
s
=
baudstring
[
1
];
else
set_baud
(
tty
,
strip_info
->
user_baud
);
else
s
=
baudstring
[
1
];
/* For now */
}
else
set_baud
(
tty
,
strip_info
->
user_baud
);
}
}
tty
->
driver
.
write
(
tty
,
0
,
s
.
string
,
s
.
length
);
tty
->
driver
.
write
(
tty
,
0
,
s
.
string
,
s
.
length
);
...
@@ -1352,93 +1286,84 @@ static void strip_write_some_more(struct tty_struct *tty)
...
@@ -1352,93 +1286,84 @@ static void strip_write_some_more(struct tty_struct *tty)
!
netif_running
(
&
strip_info
->
dev
))
!
netif_running
(
&
strip_info
->
dev
))
return
;
return
;
if
(
strip_info
->
tx_left
>
0
)
if
(
strip_info
->
tx_left
>
0
)
{
{
int
num_written
=
/*
tty
->
driver
.
write
(
tty
,
0
,
strip_info
->
tx_head
,
* If some data left, send it
strip_info
->
tx_left
);
* Note: There's a kernel design bug here. The write_wakeup routine has to
* know how many bytes were written in the previous call, but the number of
* bytes written is returned as the result of the tty->driver.write call,
* and there's no guarantee that the tty->driver.write routine will have
* returned before the write_wakeup routine is invoked. If the PC has fast
* Serial DMA hardware, then it's quite possible that the write could complete
* almost instantaneously, meaning that my write_wakeup routine could be
* called immediately, before tty->driver.write has had a chance to return
* the number of bytes that it wrote. In an attempt to guard against this,
* I disable interrupts around the call to tty->driver.write, although even
* this might not work on a symmetric multi-processor system.
*/
InterruptStatus
intstat
=
DisableInterrupts
();
int
num_written
=
tty
->
driver
.
write
(
tty
,
0
,
strip_info
->
tx_head
,
strip_info
->
tx_left
);
strip_info
->
tx_left
-=
num_written
;
strip_info
->
tx_left
-=
num_written
;
strip_info
->
tx_head
+=
num_written
;
strip_info
->
tx_head
+=
num_written
;
#ifdef EXT_COUNTERS
#ifdef EXT_COUNTERS
strip_info
->
tx_sbytes
+=
num_written
;
strip_info
->
tx_sbytes
+=
num_written
;
#endif
#endif
RestoreInterrupts
(
intstat
);
}
else
{
/* Else start transmission of another packet */
}
else
/* Else start transmission of another packet */
{
tty
->
flags
&=
~
(
1
<<
TTY_DO_WRITE_WAKEUP
);
tty
->
flags
&=
~
(
1
<<
TTY_DO_WRITE_WAKEUP
);
strip_unlock
(
strip_info
);
strip_unlock
(
strip_info
);
}
}
}
}
static
__u8
*
add_checksum
(
__u8
*
buffer
,
__u8
*
end
)
static
__u8
*
add_checksum
(
__u8
*
buffer
,
__u8
*
end
)
{
{
__u16
sum
=
0
;
__u16
sum
=
0
;
__u8
*
p
=
buffer
;
__u8
*
p
=
buffer
;
while
(
p
<
end
)
sum
+=
*
p
++
;
while
(
p
<
end
)
end
[
3
]
=
hextable
[
sum
&
0xF
];
sum
>>=
4
;
sum
+=
*
p
++
;
end
[
2
]
=
hextable
[
sum
&
0xF
];
sum
>>=
4
;
end
[
3
]
=
hextable
[
sum
&
0xF
];
end
[
1
]
=
hextable
[
sum
&
0xF
];
sum
>>=
4
;
sum
>>=
4
;
end
[
2
]
=
hextable
[
sum
&
0xF
];
sum
>>=
4
;
end
[
1
]
=
hextable
[
sum
&
0xF
];
sum
>>=
4
;
end
[
0
]
=
hextable
[
sum
&
0xF
];
end
[
0
]
=
hextable
[
sum
&
0xF
];
return
(
end
+
4
);
return
(
end
+
4
);
}
}
static
unsigned
char
*
strip_make_packet
(
unsigned
char
*
buffer
,
struct
strip
*
strip_info
,
struct
sk_buff
*
skb
)
static
unsigned
char
*
strip_make_packet
(
unsigned
char
*
buffer
,
struct
strip
*
strip_info
,
struct
sk_buff
*
skb
)
{
{
__u8
*
ptr
=
buffer
;
__u8
*
ptr
=
buffer
;
__u8
*
stuffstate
=
NULL
;
__u8
*
stuffstate
=
NULL
;
STRIP_Header
*
header
=
(
STRIP_Header
*
)
skb
->
data
;
STRIP_Header
*
header
=
(
STRIP_Header
*
)
skb
->
data
;
MetricomAddress
haddr
=
header
->
dst_addr
;
MetricomAddress
haddr
=
header
->
dst_addr
;
int
len
=
skb
->
len
-
sizeof
(
STRIP_Header
);
int
len
=
skb
->
len
-
sizeof
(
STRIP_Header
);
MetricomKey
key
;
MetricomKey
key
;
/*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len);
*/
/*HexDump("strip_make_packet", strip_info, skb->data, skb->data + skb->len);
*/
if
(
header
->
protocol
==
htons
(
ETH_P_IP
))
key
=
SIP0Key
;
if
(
header
->
protocol
==
htons
(
ETH_P_IP
))
else
if
(
header
->
protocol
==
htons
(
ETH_P_ARP
))
key
=
ARP0Key
;
key
=
SIP0Key
;
else
else
if
(
header
->
protocol
==
htons
(
ETH_P_ARP
))
{
key
=
ARP0Key
;
printk
(
KERN_ERR
"%s: strip_make_packet: Unknown packet type 0x%04X
\n
"
,
else
{
printk
(
KERN_ERR
"%s: strip_make_packet: Unknown packet type 0x%04X
\n
"
,
strip_info
->
dev
.
name
,
ntohs
(
header
->
protocol
));
strip_info
->
dev
.
name
,
ntohs
(
header
->
protocol
));
return
(
NULL
);
return
(
NULL
);
}
}
if
(
len
>
strip_info
->
mtu
)
if
(
len
>
strip_info
->
mtu
)
{
{
printk
(
KERN_ERR
printk
(
KERN_ERR
"%s: Dropping oversized transmit packet: %d bytes
\n
"
,
"%s: Dropping oversized transmit packet: %d bytes
\n
"
,
strip_info
->
dev
.
name
,
len
);
strip_info
->
dev
.
name
,
len
);
return
(
NULL
);
return
(
NULL
);
}
}
/*
/*
* If we're sending to ourselves, discard the packet.
* If we're sending to ourselves, discard the packet.
* (Metricom radios choke if they try to send a packet to their own address.)
* (Metricom radios choke if they try to send a packet to their own address.)
*/
*/
if
(
!
memcmp
(
haddr
.
c
,
strip_info
->
true_dev_addr
.
c
,
sizeof
(
haddr
)))
if
(
!
memcmp
(
haddr
.
c
,
strip_info
->
true_dev_addr
.
c
,
sizeof
(
haddr
)))
{
{
printk
(
KERN_ERR
"%s: Dropping packet addressed to self
\n
"
,
printk
(
KERN_ERR
"%s: Dropping packet addressed to self
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
return
(
NULL
);
return
(
NULL
);
}
}
/*
/*
* If this is a broadcast packet, send it to our designated Metricom
* If this is a broadcast packet, send it to our designated Metricom
* 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
* 'broadcast hub' radio (First byte of address being 0xFF means broadcast)
*/
*/
if
(
haddr
.
c
[
0
]
==
0xFF
)
if
(
haddr
.
c
[
0
]
==
0xFF
)
{
{
u32
brd
=
0
;
u32
brd
=
0
;
struct
in_device
*
in_dev
=
in_dev_get
(
&
strip_info
->
dev
);
struct
in_device
*
in_dev
=
in_dev_get
(
&
strip_info
->
dev
);
if
(
in_dev
==
NULL
)
if
(
in_dev
==
NULL
)
...
@@ -1450,17 +1375,19 @@ static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *str
...
@@ -1450,17 +1375,19 @@ static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *str
in_dev_put
(
in_dev
);
in_dev_put
(
in_dev
);
/* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */
/* arp_query returns 1 if it succeeds in looking up the address, 0 if it fails */
if
(
!
arp_query
(
haddr
.
c
,
brd
,
&
strip_info
->
dev
))
if
(
!
arp_query
(
haddr
.
c
,
brd
,
&
strip_info
->
dev
))
{
{
printk
(
KERN_ERR
printk
(
KERN_ERR
"%s: Unable to send packet (no broadcast hub configured)
\n
"
,
"%s: Unable to send packet (no broadcast hub configured)
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
return
(
NULL
);
return
(
NULL
);
}
}
/*
/*
* If we are the broadcast hub, don't bother sending to ourselves.
* If we are the broadcast hub, don't bother sending to ourselves.
* (Metricom radios choke if they try to send a packet to their own address.)
* (Metricom radios choke if they try to send a packet to their own address.)
*/
*/
if
(
!
memcmp
(
haddr
.
c
,
strip_info
->
true_dev_addr
.
c
,
sizeof
(
haddr
)))
return
(
NULL
);
if
(
!
memcmp
(
haddr
.
c
,
strip_info
->
true_dev_addr
.
c
,
sizeof
(
haddr
)))
return
(
NULL
);
}
}
*
ptr
++
=
0x0D
;
*
ptr
++
=
0x0D
;
...
@@ -1480,32 +1407,35 @@ static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *str
...
@@ -1480,32 +1407,35 @@ static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *str
*
ptr
++
=
key
.
c
[
2
];
*
ptr
++
=
key
.
c
[
2
];
*
ptr
++
=
key
.
c
[
3
];
*
ptr
++
=
key
.
c
[
3
];
ptr
=
StuffData
(
skb
->
data
+
sizeof
(
STRIP_Header
),
len
,
ptr
,
&
stuffstate
);
ptr
=
StuffData
(
skb
->
data
+
sizeof
(
STRIP_Header
),
len
,
ptr
,
&
stuffstate
);
if
(
strip_info
->
firmware_level
>=
ChecksummedMessages
)
ptr
=
add_checksum
(
buffer
+
1
,
ptr
);
if
(
strip_info
->
firmware_level
>=
ChecksummedMessages
)
ptr
=
add_checksum
(
buffer
+
1
,
ptr
);
*
ptr
++
=
0x0D
;
*
ptr
++
=
0x0D
;
return
(
ptr
);
return
(
ptr
);
}
}
static
void
strip_send
(
struct
strip
*
strip_info
,
struct
sk_buff
*
skb
)
static
void
strip_send
(
struct
strip
*
strip_info
,
struct
sk_buff
*
skb
)
{
{
MetricomAddress
haddr
;
MetricomAddress
haddr
;
unsigned
char
*
ptr
=
strip_info
->
tx_buff
;
unsigned
char
*
ptr
=
strip_info
->
tx_buff
;
int
doreset
=
(
long
)
jiffies
-
strip_info
->
watchdog_doreset
>=
0
;
int
doreset
=
(
long
)
jiffies
-
strip_info
->
watchdog_doreset
>=
0
;
int
doprobe
=
(
long
)
jiffies
-
strip_info
->
watchdog_doprobe
>=
0
&&
!
doreset
;
int
doprobe
=
(
long
)
jiffies
-
strip_info
->
watchdog_doprobe
>=
0
&&
!
doreset
;
u32
addr
,
brd
;
u32
addr
,
brd
;
/*
/*
* 1. If we have a packet, encapsulate it and put it in the buffer
* 1. If we have a packet, encapsulate it and put it in the buffer
*/
*/
if
(
skb
)
if
(
skb
)
{
{
char
*
newptr
=
strip_make_packet
(
ptr
,
strip_info
,
skb
);
char
*
newptr
=
strip_make_packet
(
ptr
,
strip_info
,
skb
);
strip_info
->
tx_pps_count
++
;
strip_info
->
tx_pps_count
++
;
if
(
!
newptr
)
strip_info
->
tx_dropped
++
;
if
(
!
newptr
)
else
strip_info
->
tx_dropped
++
;
{
else
{
ptr
=
newptr
;
ptr
=
newptr
;
strip_info
->
sx_pps_count
++
;
strip_info
->
sx_pps_count
++
;
strip_info
->
tx_packets
++
;
/* Count another successful packet */
strip_info
->
tx_packets
++
;
/* Count another successful packet */
...
@@ -1513,26 +1443,27 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
...
@@ -1513,26 +1443,27 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
strip_info
->
tx_bytes
+=
skb
->
len
;
strip_info
->
tx_bytes
+=
skb
->
len
;
strip_info
->
tx_rbytes
+=
ptr
-
strip_info
->
tx_buff
;
strip_info
->
tx_rbytes
+=
ptr
-
strip_info
->
tx_buff
;
#endif
#endif
/*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);
*/
/*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);
*/
/*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);
*/
/*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);
*/
}
}
}
}
/*
/*
* 2. If it is time for another tickle, tack it on, after the packet
* 2. If it is time for another tickle, tack it on, after the packet
*/
*/
if
(
doprobe
)
if
(
doprobe
)
{
{
StringDescriptor
ts
=
CommandString
[
strip_info
->
next_command
];
StringDescriptor
ts
=
CommandString
[
strip_info
->
next_command
];
#if TICKLE_TIMERS
#if TICKLE_TIMERS
{
{
struct
timeval
tv
;
struct
timeval
tv
;
do_gettimeofday
(
&
tv
);
do_gettimeofday
(
&
tv
);
printk
(
KERN_INFO
"**** Sending tickle string %d at %02d.%06d
\n
"
,
printk
(
KERN_INFO
"**** Sending tickle string %d at %02d.%06d
\n
"
,
strip_info
->
next_command
,
tv
.
tv_sec
%
100
,
tv
.
tv_usec
);
strip_info
->
next_command
,
tv
.
tv_sec
%
100
,
tv
.
tv_usec
);
}
}
#endif
#endif
if
(
ptr
==
strip_info
->
tx_buff
)
*
ptr
++
=
0x0D
;
if
(
ptr
==
strip_info
->
tx_buff
)
*
ptr
++
=
0x0D
;
*
ptr
++
=
'*'
;
/* First send "**" to provoke an error message */
*
ptr
++
=
'*'
;
/* First send "**" to provoke an error message */
*
ptr
++
=
'*'
;
*
ptr
++
=
'*'
;
...
@@ -1541,21 +1472,24 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
...
@@ -1541,21 +1472,24 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
memcpy
(
ptr
,
ts
.
string
,
ts
.
length
);
memcpy
(
ptr
,
ts
.
string
,
ts
.
length
);
/* Add a checksum ? */
/* Add a checksum ? */
if
(
strip_info
->
firmware_level
<
ChecksummedMessages
)
ptr
+=
ts
.
length
;
if
(
strip_info
->
firmware_level
<
ChecksummedMessages
)
else
ptr
=
add_checksum
(
ptr
,
ptr
+
ts
.
length
);
ptr
+=
ts
.
length
;
else
ptr
=
add_checksum
(
ptr
,
ptr
+
ts
.
length
);
*
ptr
++
=
0x0D
;
/* Terminate the command with a <CR> */
*
ptr
++
=
0x0D
;
/* Terminate the command with a <CR> */
/* Cycle to next periodic command? */
/* Cycle to next periodic command? */
if
(
strip_info
->
firmware_level
>=
StructuredMessages
)
if
(
strip_info
->
firmware_level
>=
StructuredMessages
)
if
(
++
strip_info
->
next_command
>=
ELEMENTS_OF
(
CommandString
))
if
(
++
strip_info
->
next_command
>=
ELEMENTS_OF
(
CommandString
))
strip_info
->
next_command
=
0
;
strip_info
->
next_command
=
0
;
#ifdef EXT_COUNTERS
#ifdef EXT_COUNTERS
strip_info
->
tx_ebytes
+=
ts
.
length
;
strip_info
->
tx_ebytes
+=
ts
.
length
;
#endif
#endif
strip_info
->
watchdog_doprobe
=
jiffies
+
10
*
HZ
;
strip_info
->
watchdog_doprobe
=
jiffies
+
10
*
HZ
;
strip_info
->
watchdog_doreset
=
jiffies
+
1
*
HZ
;
strip_info
->
watchdog_doreset
=
jiffies
+
1
*
HZ
;
/*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);
*/
/*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);
*/
}
}
/*
/*
...
@@ -1569,14 +1503,18 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
...
@@ -1569,14 +1503,18 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
* 4. Debugging check to make sure we're not overflowing the buffer.
* 4. Debugging check to make sure we're not overflowing the buffer.
*/
*/
if
(
strip_info
->
tx_size
-
strip_info
->
tx_left
<
20
)
if
(
strip_info
->
tx_size
-
strip_info
->
tx_left
<
20
)
printk
(
KERN_ERR
"%s: Sending%5d bytes;%5d bytes free.
\n
"
,
strip_info
->
dev
.
name
,
printk
(
KERN_ERR
"%s: Sending%5d bytes;%5d bytes free.
\n
"
,
strip_info
->
tx_left
,
strip_info
->
tx_size
-
strip_info
->
tx_left
);
strip_info
->
dev
.
name
,
strip_info
->
tx_left
,
strip_info
->
tx_size
-
strip_info
->
tx_left
);
/*
/*
* 5. If watchdog has expired, reset the radio. Note: if there's data waiting in
* 5. If watchdog has expired, reset the radio. Note: if there's data waiting in
* the buffer, strip_write_some_more will send it after the reset has finished
* the buffer, strip_write_some_more will send it after the reset has finished
*/
*/
if
(
doreset
)
{
ResetRadio
(
strip_info
);
return
;
}
if
(
doreset
)
{
ResetRadio
(
strip_info
);
return
;
}
if
(
1
)
{
if
(
1
)
{
struct
in_device
*
in_dev
=
in_dev_get
(
&
strip_info
->
dev
);
struct
in_device
*
in_dev
=
in_dev_get
(
&
strip_info
->
dev
);
...
@@ -1607,20 +1545,20 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
...
@@ -1607,20 +1545,20 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
* being sent, when in fact they are not, because they are all being dropped
* being sent, when in fact they are not, because they are all being dropped
* in the strip_make_packet routine.
* in the strip_make_packet routine.
*/
*/
if
(
strip_info
->
working
&&
(
long
)
jiffies
-
strip_info
->
gratuitous_arp
>=
0
&&
if
(
strip_info
->
working
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
))
&&
&&
(
long
)
jiffies
-
strip_info
->
gratuitous_arp
>=
0
arp_query
(
haddr
.
c
,
brd
,
&
strip_info
->
dev
))
&&
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
{
sizeof
(
zero_address
))
&&
arp_query
(
haddr
.
c
,
brd
,
&
strip_info
->
dev
))
{
/*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n",
/*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n",
strip_info->dev.name, strip_info->arp_interval / HZ);*/
strip_info->dev.name, strip_info->arp_interval / HZ); */
strip_info
->
gratuitous_arp
=
jiffies
+
strip_info
->
arp_interval
;
strip_info
->
gratuitous_arp
=
jiffies
+
strip_info
->
arp_interval
;
strip_info
->
arp_interval
*=
2
;
strip_info
->
arp_interval
*=
2
;
if
(
strip_info
->
arp_interval
>
MaxARPInterval
)
if
(
strip_info
->
arp_interval
>
MaxARPInterval
)
strip_info
->
arp_interval
=
MaxARPInterval
;
strip_info
->
arp_interval
=
MaxARPInterval
;
if
(
addr
)
if
(
addr
)
arp_send
(
arp_send
(
ARPOP_REPLY
,
ETH_P_ARP
,
addr
,
/* Target address of ARP packet is our address */
ARPOP_REPLY
,
ETH_P_ARP
,
addr
,
/* Target address of ARP packet is our address */
&
strip_info
->
dev
,
/* Device to send packet on */
&
strip_info
->
dev
,
/* Device to send packet on */
addr
,
/* Source IP address this ARP packet comes from */
addr
,
/* Source IP address this ARP packet comes from */
NULL
,
/* Destination HW address is NULL (broadcast it) */
NULL
,
/* Destination HW address is NULL (broadcast it) */
...
@@ -1637,28 +1575,25 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
...
@@ -1637,28 +1575,25 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb)
/* Encapsulate a datagram and kick it into a TTY queue. */
/* Encapsulate a datagram and kick it into a TTY queue. */
static
int
strip_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
static
int
strip_xmit
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
unsigned
long
flags
;
if
(
!
netif_running
(
dev
))
if
(
!
netif_running
(
dev
))
{
{
printk
(
KERN_ERR
"%s: xmit call when iface is down
\n
"
,
printk
(
KERN_ERR
"%s: xmit call when iface is down
\n
"
,
dev
->
name
);
dev
->
name
);
return
(
1
);
return
(
1
);
}
}
netif_stop_queue
(
dev
);
netif_stop_queue
(
dev
);
del_timer
(
&
strip_info
->
idle_timer
);
del_timer
(
&
strip_info
->
idle_timer
);
/* See if someone has been ifconfigging */
if
(
strip_info
->
mtu
!=
strip_info
->
dev
.
mtu
)
strip_changedmtu
(
strip_info
);
if
(
jiffies
-
strip_info
->
pps_timer
>
HZ
)
if
(
jiffies
-
strip_info
->
pps_timer
>
HZ
)
{
{
unsigned
long
t
=
jiffies
-
strip_info
->
pps_timer
;
unsigned
long
t
=
jiffies
-
strip_info
->
pps_timer
;
unsigned
long
rx_pps_count
=
(
strip_info
->
rx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
unsigned
long
rx_pps_count
=
(
strip_info
->
rx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
unsigned
long
tx_pps_count
=
(
strip_info
->
tx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
unsigned
long
tx_pps_count
=
(
strip_info
->
tx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
unsigned
long
sx_pps_count
=
(
strip_info
->
sx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
unsigned
long
sx_pps_count
=
(
strip_info
->
sx_pps_count
*
HZ
*
8
+
t
/
2
)
/
t
;
strip_info
->
pps_timer
=
jiffies
;
strip_info
->
pps_timer
=
jiffies
;
strip_info
->
rx_pps_count
=
0
;
strip_info
->
rx_pps_count
=
0
;
...
@@ -1680,11 +1615,18 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1680,11 +1615,18 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
strip_info
->
dev
.
name
,
sx_pps_count
/
8
);
strip_info
->
dev
.
name
,
sx_pps_count
/
8
);
}
}
spin_lock_irqsave
(
&
strip_lock
,
flags
);
/* See if someone has been ifconfigging */
if
(
strip_info
->
mtu
!=
strip_info
->
dev
.
mtu
)
strip_changedmtu
(
strip_info
);
strip_send
(
strip_info
,
skb
);
strip_send
(
strip_info
,
skb
);
spin_unlock_irqrestore
(
&
strip_lock
,
flags
);
if
(
skb
)
if
(
skb
)
dev_kfree_skb
(
skb
);
dev_kfree_skb
(
skb
);
return
(
0
)
;
return
0
;
}
}
/*
/*
...
@@ -1695,7 +1637,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
...
@@ -1695,7 +1637,7 @@ static int strip_xmit(struct sk_buff *skb, struct net_device *dev)
static
void
strip_IdleTask
(
unsigned
long
parameter
)
static
void
strip_IdleTask
(
unsigned
long
parameter
)
{
{
strip_xmit
(
NULL
,
(
struct
net_device
*
)
parameter
);
strip_xmit
(
NULL
,
(
struct
net_device
*
)
parameter
);
}
}
/*
/*
...
@@ -1710,23 +1652,25 @@ static void strip_IdleTask(unsigned long parameter)
...
@@ -1710,23 +1652,25 @@ static void strip_IdleTask(unsigned long parameter)
*/
*/
static
int
strip_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
static
int
strip_header
(
struct
sk_buff
*
skb
,
struct
net_device
*
dev
,
unsigned
short
type
,
void
*
daddr
,
void
*
saddr
,
unsigned
len
)
unsigned
short
type
,
void
*
daddr
,
void
*
saddr
,
unsigned
len
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
STRIP_Header
*
header
=
(
STRIP_Header
*
)
skb_push
(
skb
,
sizeof
(
STRIP_Header
));
STRIP_Header
*
header
=
(
STRIP_Header
*
)
skb_push
(
skb
,
sizeof
(
STRIP_Header
));
/*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type,
/*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type,
type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");
*/
type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");
*/
header
->
src_addr
=
strip_info
->
true_dev_addr
;
header
->
src_addr
=
strip_info
->
true_dev_addr
;
header
->
protocol
=
htons
(
type
);
header
->
protocol
=
htons
(
type
);
/*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);
*/
/*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);
*/
if
(
!
daddr
)
return
(
-
dev
->
hard_header_len
);
if
(
!
daddr
)
return
(
-
dev
->
hard_header_len
);
header
->
dst_addr
=
*
(
MetricomAddress
*
)
daddr
;
header
->
dst_addr
=
*
(
MetricomAddress
*
)
daddr
;
return
(
dev
->
hard_header_len
);
return
(
dev
->
hard_header_len
);
}
}
/*
/*
...
@@ -1744,7 +1688,7 @@ static int strip_rebuild_header(struct sk_buff *skb)
...
@@ -1744,7 +1688,7 @@ static int strip_rebuild_header(struct sk_buff *skb)
/* Arp find returns zero if if knows the address, */
/* Arp find returns zero if if knows the address, */
/* or if it doesn't know the address it sends an ARP packet and returns non-zero */
/* or if it doesn't know the address it sends an ARP packet and returns non-zero */
return
arp_find
(
header
->
dst_addr
.
c
,
skb
)
?
1
:
0
;
return
arp_find
(
header
->
dst_addr
.
c
,
skb
)
?
1
:
0
;
#else
#else
return
0
;
return
0
;
#endif
#endif
...
@@ -1763,21 +1707,25 @@ static int strip_receive_room(struct tty_struct *tty)
...
@@ -1763,21 +1707,25 @@ static int strip_receive_room(struct tty_struct *tty)
* This function parses the response to the ATS300? command,
* This function parses the response to the ATS300? command,
* extracting the radio version and serial number.
* extracting the radio version and serial number.
*/
*/
static
void
get_radio_version
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
get_radio_version
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
__u8
*
p
,
*
value_begin
,
*
value_end
;
__u8
*
p
,
*
value_begin
,
*
value_end
;
int
len
;
int
len
;
/* Determine the beginning of the second line of the payload */
/* Determine the beginning of the second line of the payload */
p
=
ptr
;
p
=
ptr
;
while
(
p
<
end
&&
*
p
!=
10
)
p
++
;
while
(
p
<
end
&&
*
p
!=
10
)
if
(
p
>=
end
)
return
;
p
++
;
if
(
p
>=
end
)
return
;
p
++
;
p
++
;
value_begin
=
p
;
value_begin
=
p
;
/* Determine the end of line */
/* Determine the end of line */
while
(
p
<
end
&&
*
p
!=
10
)
p
++
;
while
(
p
<
end
&&
*
p
!=
10
)
if
(
p
>=
end
)
return
;
p
++
;
if
(
p
>=
end
)
return
;
value_end
=
p
;
value_end
=
p
;
p
++
;
p
++
;
...
@@ -1789,16 +1737,18 @@ static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
...
@@ -1789,16 +1737,18 @@ static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
sprintf
(
strip_info
->
firmware_version
.
c
,
"%.*s"
,
len
,
value_begin
);
sprintf
(
strip_info
->
firmware_version
.
c
,
"%.*s"
,
len
,
value_begin
);
/* Look for the first colon */
/* Look for the first colon */
while
(
p
<
end
&&
*
p
!=
':'
)
p
++
;
while
(
p
<
end
&&
*
p
!=
':'
)
if
(
p
>=
end
)
return
;
p
++
;
if
(
p
>=
end
)
return
;
/* Skip over the space */
/* Skip over the space */
p
+=
2
;
p
+=
2
;
len
=
sizeof
(
SerialNumber
)
-
1
;
len
=
sizeof
(
SerialNumber
)
-
1
;
if
(
p
+
len
<=
end
)
{
if
(
p
+
len
<=
end
)
{
sprintf
(
strip_info
->
serial_number
.
c
,
"%.*s"
,
len
,
p
);
sprintf
(
strip_info
->
serial_number
.
c
,
"%.*s"
,
len
,
p
);
}
}
else
{
else
{
printk
(
KERN_DEBUG
printk
(
KERN_DEBUG
"STRIP: radio serial number shorter (%d) than expected (%d)
\n
"
,
"STRIP: radio serial number shorter (%d) than expected (%d)
\n
"
,
end
-
p
,
len
);
end
-
p
,
len
);
}
}
}
}
...
@@ -1807,16 +1757,16 @@ static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
...
@@ -1807,16 +1757,16 @@ static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end)
* This function parses the response to the ATS325? command,
* This function parses the response to the ATS325? command,
* extracting the radio battery voltage.
* extracting the radio battery voltage.
*/
*/
static
void
get_radio_voltage
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
get_radio_voltage
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
int
len
;
int
len
;
len
=
sizeof
(
BatteryVoltage
)
-
1
;
len
=
sizeof
(
BatteryVoltage
)
-
1
;
if
(
ptr
+
len
<=
end
)
{
if
(
ptr
+
len
<=
end
)
{
sprintf
(
strip_info
->
battery_voltage
.
c
,
"%.*s"
,
len
,
ptr
);
sprintf
(
strip_info
->
battery_voltage
.
c
,
"%.*s"
,
len
,
ptr
);
}
}
else
{
else
{
printk
(
KERN_DEBUG
printk
(
KERN_DEBUG
"STRIP: radio voltage string shorter (%d) than expected (%d)
\n
"
,
"STRIP: radio voltage string shorter (%d) than expected (%d)
\n
"
,
end
-
ptr
,
len
);
end
-
ptr
,
len
);
}
}
}
}
...
@@ -1825,55 +1775,62 @@ static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end)
...
@@ -1825,55 +1775,62 @@ static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end)
* This function parses the responses to the AT~LA and ATS311 commands,
* This function parses the responses to the AT~LA and ATS311 commands,
* which list the radio's neighbours.
* which list the radio's neighbours.
*/
*/
static
void
get_radio_neighbours
(
MetricomNodeTable
*
table
,
__u8
*
ptr
,
__u8
*
end
)
static
void
get_radio_neighbours
(
MetricomNodeTable
*
table
,
__u8
*
ptr
,
__u8
*
end
)
{
{
table
->
num_nodes
=
0
;
table
->
num_nodes
=
0
;
while
(
ptr
<
end
&&
table
->
num_nodes
<
NODE_TABLE_SIZE
)
while
(
ptr
<
end
&&
table
->
num_nodes
<
NODE_TABLE_SIZE
)
{
{
MetricomNode
*
node
=
&
table
->
node
[
table
->
num_nodes
++
];
MetricomNode
*
node
=
&
table
->
node
[
table
->
num_nodes
++
];
char
*
dst
=
node
->
c
,
*
limit
=
dst
+
sizeof
(
*
node
)
-
1
;
char
*
dst
=
node
->
c
,
*
limit
=
dst
+
sizeof
(
*
node
)
-
1
;
while
(
ptr
<
end
&&
*
ptr
<=
32
)
ptr
++
;
while
(
ptr
<
end
&&
*
ptr
<=
32
)
while
(
ptr
<
end
&&
dst
<
limit
&&
*
ptr
!=
10
)
*
dst
++
=
*
ptr
++
;
ptr
++
;
while
(
ptr
<
end
&&
dst
<
limit
&&
*
ptr
!=
10
)
*
dst
++
=
*
ptr
++
;
*
dst
++
=
0
;
*
dst
++
=
0
;
while
(
ptr
<
end
&&
ptr
[
-
1
]
!=
10
)
ptr
++
;
while
(
ptr
<
end
&&
ptr
[
-
1
]
!=
10
)
ptr
++
;
}
}
do_gettimeofday
(
&
table
->
timestamp
);
do_gettimeofday
(
&
table
->
timestamp
);
}
}
static
int
get_radio_address
(
struct
strip
*
strip_info
,
__u8
*
p
)
static
int
get_radio_address
(
struct
strip
*
strip_info
,
__u8
*
p
)
{
{
MetricomAddress
addr
;
MetricomAddress
addr
;
if
(
string_to_radio_address
(
&
addr
,
p
))
return
(
1
);
if
(
string_to_radio_address
(
&
addr
,
p
))
return
(
1
);
/* See if our radio address has changed */
/* See if our radio address has changed */
if
(
memcmp
(
strip_info
->
true_dev_addr
.
c
,
addr
.
c
,
sizeof
(
addr
)))
if
(
memcmp
(
strip_info
->
true_dev_addr
.
c
,
addr
.
c
,
sizeof
(
addr
)))
{
{
MetricomAddressString
addr_string
;
MetricomAddressString
addr_string
;
radio_address_to_string
(
&
addr
,
&
addr_string
);
radio_address_to_string
(
&
addr
,
&
addr_string
);
printk
(
KERN_INFO
"%s: Radio address = %s
\n
"
,
strip_info
->
dev
.
name
,
addr_string
.
c
);
printk
(
KERN_INFO
"%s: Radio address = %s
\n
"
,
strip_info
->
dev
.
name
,
addr_string
.
c
);
strip_info
->
true_dev_addr
=
addr
;
strip_info
->
true_dev_addr
=
addr
;
if
(
!
strip_info
->
manual_dev_addr
)
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
addr
;
if
(
!
strip_info
->
manual_dev_addr
)
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
addr
;
/* Give the radio a few seconds to get its head straight, then send an arp */
/* Give the radio a few seconds to get its head straight, then send an arp */
strip_info
->
gratuitous_arp
=
jiffies
+
15
*
HZ
;
strip_info
->
gratuitous_arp
=
jiffies
+
15
*
HZ
;
strip_info
->
arp_interval
=
1
*
HZ
;
strip_info
->
arp_interval
=
1
*
HZ
;
}
}
return
(
0
);
return
(
0
);
}
}
static
int
verify_checksum
(
struct
strip
*
strip_info
)
static
int
verify_checksum
(
struct
strip
*
strip_info
)
{
{
__u8
*
p
=
strip_info
->
sx_buff
;
__u8
*
p
=
strip_info
->
sx_buff
;
__u8
*
end
=
strip_info
->
sx_buff
+
strip_info
->
sx_count
-
4
;
__u8
*
end
=
strip_info
->
sx_buff
+
strip_info
->
sx_count
-
4
;
u_short
sum
=
(
READHEX16
(
end
[
0
])
<<
12
)
|
(
READHEX16
(
end
[
1
])
<<
8
)
|
u_short
sum
=
(
READHEX16
(
end
[
0
])
<<
12
)
|
(
READHEX16
(
end
[
1
])
<<
8
)
|
(
READHEX16
(
end
[
2
])
<<
4
)
|
(
READHEX16
(
end
[
3
]));
(
READHEX16
(
end
[
2
])
<<
4
)
|
(
READHEX16
(
end
[
3
]));
while
(
p
<
end
)
sum
-=
*
p
++
;
while
(
p
<
end
)
if
(
sum
==
0
&&
strip_info
->
firmware_level
==
StructuredMessages
)
sum
-=
*
p
++
;
{
if
(
sum
==
0
&&
strip_info
->
firmware_level
==
StructuredMessages
)
{
strip_info
->
firmware_level
=
ChecksummedMessages
;
strip_info
->
firmware_level
=
ChecksummedMessages
;
printk
(
KERN_INFO
"%s: Radio provides message checksums
\n
"
,
strip_info
->
dev
.
name
);
printk
(
KERN_INFO
"%s: Radio provides message checksums
\n
"
,
strip_info
->
dev
.
name
);
}
}
return
(
sum
==
0
);
return
(
sum
==
0
);
}
}
static
void
RecvErr
(
char
*
msg
,
struct
strip
*
strip_info
)
static
void
RecvErr
(
char
*
msg
,
struct
strip
*
strip_info
)
...
@@ -1884,56 +1841,54 @@ static void RecvErr(char *msg, struct strip *strip_info)
...
@@ -1884,56 +1841,54 @@ static void RecvErr(char *msg, struct strip *strip_info)
strip_info
->
rx_errors
++
;
strip_info
->
rx_errors
++
;
}
}
static
void
RecvErr_Message
(
struct
strip
*
strip_info
,
__u8
*
sendername
,
const
__u8
*
msg
,
u_long
len
)
static
void
RecvErr_Message
(
struct
strip
*
strip_info
,
__u8
*
sendername
,
const
__u8
*
msg
,
u_long
len
)
{
{
if
(
has_prefix
(
msg
,
len
,
"001"
))
/* Not in StarMode! */
if
(
has_prefix
(
msg
,
len
,
"001"
))
{
/* Not in StarMode! */
{
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
printk
(
KERN_INFO
"%s: Radio %s is not in StarMode
\n
"
,
printk
(
KERN_INFO
"%s: Radio %s is not in StarMode
\n
"
,
strip_info
->
dev
.
name
,
sendername
);
strip_info
->
dev
.
name
,
sendername
);
}
}
else
if
(
has_prefix
(
msg
,
len
,
"002"
))
/* Remap handle */
else
if
(
has_prefix
(
msg
,
len
,
"002"
))
{
/* Remap handle */
{
/* We ignore "Remap handle" messages for now */
/* We ignore "Remap handle" messages for now */
}
}
else
if
(
has_prefix
(
msg
,
len
,
"003"
))
/* Can't resolve name */
else
if
(
has_prefix
(
msg
,
len
,
"003"
))
{
/* Can't resolve name */
{
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
printk
(
KERN_INFO
"%s: Destination radio name is unknown
\n
"
,
printk
(
KERN_INFO
"%s: Destination radio name is unknown
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
}
}
else
if
(
has_prefix
(
msg
,
len
,
"004"
))
/* Name too small or missing */
else
if
(
has_prefix
(
msg
,
len
,
"004"
))
{
/* Name too small or missing */
{
strip_info
->
watchdog_doreset
=
jiffies
+
LongTime
;
strip_info
->
watchdog_doreset
=
jiffies
+
LongTime
;
#if TICKLE_TIMERS
#if TICKLE_TIMERS
{
{
struct
timeval
tv
;
struct
timeval
tv
;
do_gettimeofday
(
&
tv
);
do_gettimeofday
(
&
tv
);
printk
(
KERN_INFO
"**** Got ERR_004 response at %02d.%06d
\n
"
,
printk
(
KERN_INFO
"**** Got ERR_004 response at %02d.%06d
\n
"
,
tv
.
tv_sec
%
100
,
tv
.
tv_usec
);
tv
.
tv_sec
%
100
,
tv
.
tv_usec
);
}
}
#endif
#endif
if
(
!
strip_info
->
working
)
if
(
!
strip_info
->
working
)
{
{
strip_info
->
working
=
TRUE
;
strip_info
->
working
=
TRUE
;
printk
(
KERN_INFO
"%s: Radio now in starmode
\n
"
,
strip_info
->
dev
.
name
);
printk
(
KERN_INFO
"%s: Radio now in starmode
\n
"
,
strip_info
->
dev
.
name
);
/*
/*
* If the radio has just entered a working state, we should do our first
* If the radio has just entered a working state, we should do our first
* probe ASAP, so that we find out our radio address etc. without delay.
* probe ASAP, so that we find out our radio address etc. without delay.
*/
*/
strip_info
->
watchdog_doprobe
=
jiffies
;
strip_info
->
watchdog_doprobe
=
jiffies
;
}
}
if
(
strip_info
->
firmware_level
==
NoStructure
&&
sendername
)
if
(
strip_info
->
firmware_level
==
NoStructure
&&
sendername
)
{
{
strip_info
->
firmware_level
=
StructuredMessages
;
strip_info
->
firmware_level
=
StructuredMessages
;
strip_info
->
next_command
=
0
;
/* Try to enable checksums ASAP */
strip_info
->
next_command
=
0
;
/* Try to enable checksums ASAP */
printk
(
KERN_INFO
"%s: Radio provides structured messages
\n
"
,
strip_info
->
dev
.
name
);
printk
(
KERN_INFO
"%s: Radio provides structured messages
\n
"
,
strip_info
->
dev
.
name
);
}
}
if
(
strip_info
->
firmware_level
>=
StructuredMessages
)
if
(
strip_info
->
firmware_level
>=
StructuredMessages
)
{
{
/*
/*
* If this message has a valid checksum on the end, then the call to verify_checksum
* If this message has a valid checksum on the end, then the call to verify_checksum
* will elevate the firmware_level to ChecksummedMessages for us. (The actual return
* will elevate the firmware_level to ChecksummedMessages for us. (The actual return
...
@@ -1944,7 +1899,8 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
...
@@ -1944,7 +1899,8 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
* If the radio has structured messages but we don't yet have all our information about it,
* If the radio has structured messages but we don't yet have all our information about it,
* we should do probes without delay, until we have gathered all the information
* we should do probes without delay, until we have gathered all the information
*/
*/
if
(
!
GOT_ALL_RADIO_INFO
(
strip_info
))
strip_info
->
watchdog_doprobe
=
jiffies
;
if
(
!
GOT_ALL_RADIO_INFO
(
strip_info
))
strip_info
->
watchdog_doprobe
=
jiffies
;
}
}
}
}
...
@@ -1954,17 +1910,17 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
...
@@ -1954,17 +1910,17 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
else
if
(
has_prefix
(
msg
,
len
,
"006"
))
/* Header too big */
else
if
(
has_prefix
(
msg
,
len
,
"006"
))
/* Header too big */
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
else
if
(
has_prefix
(
msg
,
len
,
"007"
))
/* Body too big */
else
if
(
has_prefix
(
msg
,
len
,
"007"
))
{
/* Body too big */
{
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
printk
(
KERN_ERR
"%s: Error! Packet size too big for radio.
\n
"
,
printk
(
KERN_ERR
"%s: Error! Packet size too big for radio.
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
}
}
else
if
(
has_prefix
(
msg
,
len
,
"008"
))
/* Bad character in name */
else
if
(
has_prefix
(
msg
,
len
,
"008"
))
{
/* Bad character in name */
{
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
printk
(
KERN_ERR
"%s: Radio name contains illegal character
\n
"
,
printk
(
KERN_ERR
"%s: Radio name contains illegal character
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
}
}
...
@@ -1984,13 +1940,15 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
...
@@ -1984,13 +1940,15 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __
RecvErr
(
"Error Msg:"
,
strip_info
);
RecvErr
(
"Error Msg:"
,
strip_info
);
}
}
static
void
process_AT_response
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
process_AT_response
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
u_long
len
;
u_long
len
;
__u8
*
p
=
ptr
;
__u8
*
p
=
ptr
;
while
(
p
<
end
&&
p
[
-
1
]
!=
10
)
p
++
;
/* Skip past first newline character */
while
(
p
<
end
&&
p
[
-
1
]
!=
10
)
p
++
;
/* Skip past first newline character */
/* Now ptr points to the AT command, and p points to the text of the response. */
/* Now ptr points to the AT command, and p points to the text of the response. */
len
=
p
-
ptr
;
len
=
p
-
ptr
;
#if TICKLE_TIMERS
#if TICKLE_TIMERS
{
{
...
@@ -2001,23 +1959,31 @@ static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end)
...
@@ -2001,23 +1959,31 @@ static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end)
}
}
#endif
#endif
if
(
has_prefix
(
ptr
,
len
,
"ATS300?"
))
get_radio_version
(
strip_info
,
p
,
end
);
if
(
has_prefix
(
ptr
,
len
,
"ATS300?"
))
else
if
(
has_prefix
(
ptr
,
len
,
"ATS305?"
))
get_radio_address
(
strip_info
,
p
);
get_radio_version
(
strip_info
,
p
,
end
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS311?"
))
get_radio_neighbours
(
&
strip_info
->
poletops
,
p
,
end
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS305?"
))
else
if
(
has_prefix
(
ptr
,
len
,
"ATS319=7"
))
verify_checksum
(
strip_info
);
get_radio_address
(
strip_info
,
p
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS325?"
))
get_radio_voltage
(
strip_info
,
p
,
end
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS311?"
))
else
if
(
has_prefix
(
ptr
,
len
,
"AT~LA"
))
get_radio_neighbours
(
&
strip_info
->
portables
,
p
,
end
);
get_radio_neighbours
(
&
strip_info
->
poletops
,
p
,
end
);
else
RecvErr
(
"Unknown AT Response:"
,
strip_info
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS319=7"
))
verify_checksum
(
strip_info
);
else
if
(
has_prefix
(
ptr
,
len
,
"ATS325?"
))
get_radio_voltage
(
strip_info
,
p
,
end
);
else
if
(
has_prefix
(
ptr
,
len
,
"AT~LA"
))
get_radio_neighbours
(
&
strip_info
->
portables
,
p
,
end
);
else
RecvErr
(
"Unknown AT Response:"
,
strip_info
);
}
}
static
void
process_ACK
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
process_ACK
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
/* Currently we don't do anything with ACKs from the radio */
/* Currently we don't do anything with ACKs from the radio */
}
}
static
void
process_Info
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
static
void
process_Info
(
struct
strip
*
strip_info
,
__u8
*
ptr
,
__u8
*
end
)
{
{
if
(
ptr
+
16
>
end
)
RecvErr
(
"Bad Info Msg:"
,
strip_info
);
if
(
ptr
+
16
>
end
)
RecvErr
(
"Bad Info Msg:"
,
strip_info
);
}
}
static
struct
net_device
*
get_strip_dev
(
struct
strip
*
strip_info
)
static
struct
net_device
*
get_strip_dev
(
struct
strip
*
strip_info
)
...
@@ -2026,45 +1992,48 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
...
@@ -2026,45 +1992,48 @@ static struct net_device *get_strip_dev(struct strip *strip_info)
/* real radio hardware address, try to find another strip device that has been */
/* real radio hardware address, try to find another strip device that has been */
/* manually set to that address that we can 'transfer ownership' of this packet to */
/* manually set to that address that we can 'transfer ownership' of this packet to */
if
(
strip_info
->
manual_dev_addr
&&
if
(
strip_info
->
manual_dev_addr
&&
!
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
))
&&
!
memcmp
(
strip_info
->
dev
.
dev_addr
,
zero_address
.
c
,
memcmp
(
&
strip_info
->
true_dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
)))
sizeof
(
zero_address
))
{
&&
memcmp
(
&
strip_info
->
true_dev_addr
,
zero_address
.
c
,
sizeof
(
zero_address
)))
{
struct
net_device
*
dev
;
struct
net_device
*
dev
;
read_lock_bh
(
&
dev_base_lock
);
read_lock_bh
(
&
dev_base_lock
);
dev
=
dev_base
;
dev
=
dev_base
;
while
(
dev
)
while
(
dev
)
{
{
if
(
dev
->
type
==
strip_info
->
dev
.
type
&&
if
(
dev
->
type
==
strip_info
->
dev
.
type
&&
!
memcmp
(
dev
->
dev_addr
,
&
strip_info
->
true_dev_addr
,
sizeof
(
MetricomAddress
)))
!
memcmp
(
dev
->
dev_addr
,
{
&
strip_info
->
true_dev_addr
,
printk
(
KERN_INFO
"%s: Transferred packet ownership to %s.
\n
"
,
sizeof
(
MetricomAddress
)))
{
printk
(
KERN_INFO
"%s: Transferred packet ownership to %s.
\n
"
,
strip_info
->
dev
.
name
,
dev
->
name
);
strip_info
->
dev
.
name
,
dev
->
name
);
read_unlock_bh
(
&
dev_base_lock
);
read_unlock_bh
(
&
dev_base_lock
);
return
(
dev
);
return
(
dev
);
}
}
dev
=
dev
->
next
;
dev
=
dev
->
next
;
}
}
read_unlock_bh
(
&
dev_base_lock
);
read_unlock_bh
(
&
dev_base_lock
);
}
}
return
(
&
strip_info
->
dev
);
return
(
&
strip_info
->
dev
);
}
}
/*
/*
* Send one completely decapsulated datagram to the next layer.
* Send one completely decapsulated datagram to the next layer.
*/
*/
static
void
deliver_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u16
packetlen
)
static
void
deliver_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u16
packetlen
)
{
{
struct
sk_buff
*
skb
=
dev_alloc_skb
(
sizeof
(
STRIP_Header
)
+
packetlen
);
struct
sk_buff
*
skb
=
dev_alloc_skb
(
sizeof
(
STRIP_Header
)
+
packetlen
);
if
(
!
skb
)
if
(
!
skb
)
{
{
printk
(
KERN_ERR
"%s: memory squeeze, dropping packet.
\n
"
,
printk
(
KERN_ERR
"%s: memory squeeze, dropping packet.
\n
"
,
strip_info
->
dev
.
name
);
strip_info
->
dev
.
name
);
strip_info
->
rx_dropped
++
;
strip_info
->
rx_dropped
++
;
}
}
else
{
else
memcpy
(
skb_put
(
skb
,
sizeof
(
STRIP_Header
)),
header
,
{
sizeof
(
STRIP_Header
));
memcpy
(
skb_put
(
skb
,
sizeof
(
STRIP_Header
)),
header
,
sizeof
(
STRIP_Header
));
memcpy
(
skb_put
(
skb
,
packetlen
),
strip_info
->
rx_buff
,
memcpy
(
skb_put
(
skb
,
packetlen
),
strip_info
->
rx_buff
,
packetlen
);
packetlen
);
skb
->
dev
=
get_strip_dev
(
strip_info
);
skb
->
dev
=
get_strip_dev
(
strip_info
);
skb
->
protocol
=
header
->
protocol
;
skb
->
protocol
=
header
->
protocol
;
skb
->
mac
.
raw
=
skb
->
data
;
skb
->
mac
.
raw
=
skb
->
data
;
...
@@ -2085,40 +2054,39 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header *header, __u16
...
@@ -2085,40 +2054,39 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header *header, __u16
}
}
}
}
static
void
process_IP_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u8
*
ptr
,
__u8
*
end
)
static
void
process_IP_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u8
*
ptr
,
__u8
*
end
)
{
{
__u16
packetlen
;
__u16
packetlen
;
/* Decode start of the IP packet header */
/* Decode start of the IP packet header */
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
,
4
);
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
,
4
);
if
(
!
ptr
)
if
(
!
ptr
)
{
{
RecvErr
(
"IP Packet too short"
,
strip_info
);
RecvErr
(
"IP Packet too short"
,
strip_info
);
return
;
return
;
}
}
packetlen
=
((
__u16
)
strip_info
->
rx_buff
[
2
]
<<
8
)
|
strip_info
->
rx_buff
[
3
];
packetlen
=
((
__u16
)
strip_info
->
rx_buff
[
2
]
<<
8
)
|
strip_info
->
rx_buff
[
3
];
if
(
packetlen
>
MAX_RECV_MTU
)
if
(
packetlen
>
MAX_RECV_MTU
)
{
{
printk
(
KERN_INFO
"%s: Dropping oversized received IP packet: %d bytes
\n
"
,
printk
(
KERN_INFO
"%s: Dropping oversized received IP packet: %d bytes
\n
"
,
strip_info
->
dev
.
name
,
packetlen
);
strip_info
->
dev
.
name
,
packetlen
);
strip_info
->
rx_dropped
++
;
strip_info
->
rx_dropped
++
;
return
;
return
;
}
}
/*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev.name, packetlen);
*/
/*printk(KERN_INFO "%s: Got %d byte IP packet\n", strip_info->dev.name, packetlen);
*/
/* Decode remainder of the IP packet */
/* Decode remainder of the IP packet */
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
+
4
,
packetlen
-
4
);
ptr
=
if
(
!
ptr
)
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
+
4
,
packetlen
-
4
);
{
if
(
!
ptr
)
{
RecvErr
(
"IP Packet too short"
,
strip_info
);
RecvErr
(
"IP Packet too short"
,
strip_info
);
return
;
return
;
}
}
if
(
ptr
<
end
)
if
(
ptr
<
end
)
{
{
RecvErr
(
"IP Packet too long"
,
strip_info
);
RecvErr
(
"IP Packet too long"
,
strip_info
);
return
;
return
;
}
}
...
@@ -2128,24 +2096,25 @@ static void process_IP_packet(struct strip *strip_info, STRIP_Header *header, __
...
@@ -2128,24 +2096,25 @@ static void process_IP_packet(struct strip *strip_info, STRIP_Header *header, __
deliver_packet
(
strip_info
,
header
,
packetlen
);
deliver_packet
(
strip_info
,
header
,
packetlen
);
}
}
static
void
process_ARP_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u8
*
ptr
,
__u8
*
end
)
static
void
process_ARP_packet
(
struct
strip
*
strip_info
,
STRIP_Header
*
header
,
__u8
*
ptr
,
__u8
*
end
)
{
{
__u16
packetlen
;
__u16
packetlen
;
struct
arphdr
*
arphdr
=
(
struct
arphdr
*
)
strip_info
->
rx_buff
;
struct
arphdr
*
arphdr
=
(
struct
arphdr
*
)
strip_info
->
rx_buff
;
/* Decode start of the ARP packet */
/* Decode start of the ARP packet */
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
,
8
);
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
,
8
);
if
(
!
ptr
)
if
(
!
ptr
)
{
{
RecvErr
(
"ARP Packet too short"
,
strip_info
);
RecvErr
(
"ARP Packet too short"
,
strip_info
);
return
;
return
;
}
}
packetlen
=
8
+
(
arphdr
->
ar_hln
+
arphdr
->
ar_pln
)
*
2
;
packetlen
=
8
+
(
arphdr
->
ar_hln
+
arphdr
->
ar_pln
)
*
2
;
if
(
packetlen
>
MAX_RECV_MTU
)
if
(
packetlen
>
MAX_RECV_MTU
)
{
{
printk
(
KERN_INFO
printk
(
KERN_INFO
"%s: Dropping oversized received ARP packet: %d bytes
\n
"
,
"%s: Dropping oversized received ARP packet: %d bytes
\n
"
,
strip_info
->
dev
.
name
,
packetlen
);
strip_info
->
dev
.
name
,
packetlen
);
strip_info
->
rx_dropped
++
;
strip_info
->
rx_dropped
++
;
return
;
return
;
...
@@ -2153,18 +2122,17 @@ static void process_ARP_packet(struct strip *strip_info, STRIP_Header *header, _
...
@@ -2153,18 +2122,17 @@ static void process_ARP_packet(struct strip *strip_info, STRIP_Header *header, _
/*printk(KERN_INFO "%s: Got %d byte ARP %s\n",
/*printk(KERN_INFO "%s: Got %d byte ARP %s\n",
strip_info->dev.name, packetlen,
strip_info->dev.name, packetlen,
ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply");
*/
ntohs(arphdr->ar_op) == ARPOP_REQUEST ? "request" : "reply");
*/
/* Decode remainder of the ARP packet */
/* Decode remainder of the ARP packet */
ptr
=
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
+
8
,
packetlen
-
8
);
ptr
=
if
(
!
ptr
)
UnStuffData
(
ptr
,
end
,
strip_info
->
rx_buff
+
8
,
packetlen
-
8
);
{
if
(
!
ptr
)
{
RecvErr
(
"ARP Packet too short"
,
strip_info
);
RecvErr
(
"ARP Packet too short"
,
strip_info
);
return
;
return
;
}
}
if
(
ptr
<
end
)
if
(
ptr
<
end
)
{
{
RecvErr
(
"ARP Packet too long"
,
strip_info
);
RecvErr
(
"ARP Packet too long"
,
strip_info
);
return
;
return
;
}
}
...
@@ -2189,15 +2157,22 @@ static void process_text_message(struct strip *strip_info)
...
@@ -2189,15 +2157,22 @@ static void process_text_message(struct strip *strip_info)
/* Check for anything that looks like it might be our radio name */
/* Check for anything that looks like it might be our radio name */
/* (This is here for backwards compatibility with old firmware) */
/* (This is here for backwards compatibility with old firmware) */
if
(
len
==
9
&&
get_radio_address
(
strip_info
,
msg
)
==
0
)
return
;
if
(
len
==
9
&&
get_radio_address
(
strip_info
,
msg
)
==
0
)
return
;
if
(
text_equal
(
msg
,
len
,
"OK"
))
return
;
/* Ignore 'OK' responses from prior commands */
if
(
text_equal
(
msg
,
len
,
"OK"
))
if
(
text_equal
(
msg
,
len
,
"ERROR"
))
return
;
/* Ignore 'ERROR' messages */
return
;
/* Ignore 'OK' responses from prior commands */
if
(
has_prefix
(
msg
,
len
,
"ate0q1"
))
return
;
/* Ignore character echo back from the radio */
if
(
text_equal
(
msg
,
len
,
"ERROR"
))
return
;
/* Ignore 'ERROR' messages */
if
(
has_prefix
(
msg
,
len
,
"ate0q1"
))
return
;
/* Ignore character echo back from the radio */
/* Catch other error messages */
/* Catch other error messages */
/* (This is here for backwards compatibility with old firmware) */
/* (This is here for backwards compatibility with old firmware) */
if
(
has_prefix
(
msg
,
len
,
"ERR_"
))
{
RecvErr_Message
(
strip_info
,
NULL
,
&
msg
[
4
],
len
-
4
);
return
;
}
if
(
has_prefix
(
msg
,
len
,
"ERR_"
))
{
RecvErr_Message
(
strip_info
,
NULL
,
&
msg
[
4
],
len
-
4
);
return
;
}
RecvErr
(
"No initial *"
,
strip_info
);
RecvErr
(
"No initial *"
,
strip_info
);
}
}
...
@@ -2219,19 +2194,24 @@ static void process_message(struct strip *strip_info)
...
@@ -2219,19 +2194,24 @@ static void process_message(struct strip *strip_info)
__u8
sendername
[
32
],
*
sptr
=
sendername
;
__u8
sendername
[
32
],
*
sptr
=
sendername
;
MetricomKey
key
;
MetricomKey
key
;
/*HexDump("Receiving", strip_info, ptr, end);
*/
/*HexDump("Receiving", strip_info, ptr, end);
*/
/* Check for start of address marker, and then skip over it */
/* Check for start of address marker, and then skip over it */
if
(
*
ptr
==
'*'
)
ptr
++
;
if
(
*
ptr
==
'*'
)
else
{
process_text_message
(
strip_info
);
return
;
}
ptr
++
;
else
{
process_text_message
(
strip_info
);
return
;
}
/* Copy out the return address */
/* Copy out the return address */
while
(
ptr
<
end
&&
*
ptr
!=
'*'
&&
sptr
<
ARRAY_END
(
sendername
)
-
1
)
*
sptr
++
=
*
ptr
++
;
while
(
ptr
<
end
&&
*
ptr
!=
'*'
&&
sptr
<
ARRAY_END
(
sendername
)
-
1
)
*
sptr
++
=
*
ptr
++
;
*
sptr
=
0
;
/* Null terminate the sender name */
*
sptr
=
0
;
/* Null terminate the sender name */
/* Check for end of address marker, and skip over it */
/* Check for end of address marker, and skip over it */
if
(
ptr
>=
end
||
*
ptr
!=
'*'
)
if
(
ptr
>=
end
||
*
ptr
!=
'*'
)
{
{
RecvErr
(
"No second *"
,
strip_info
);
RecvErr
(
"No second *"
,
strip_info
);
return
;
return
;
}
}
...
@@ -2239,15 +2219,13 @@ static void process_message(struct strip *strip_info)
...
@@ -2239,15 +2219,13 @@ static void process_message(struct strip *strip_info)
/* If the sender name is "&COMMAND", ignore this 'packet' */
/* If the sender name is "&COMMAND", ignore this 'packet' */
/* (This is here for backwards compatibility with old firmware) */
/* (This is here for backwards compatibility with old firmware) */
if
(
!
strcmp
(
sendername
,
"&COMMAND"
))
if
(
!
strcmp
(
sendername
,
"&COMMAND"
))
{
{
strip_info
->
firmware_level
=
NoStructure
;
strip_info
->
firmware_level
=
NoStructure
;
strip_info
->
next_command
=
CompatibilityCommand
;
strip_info
->
next_command
=
CompatibilityCommand
;
return
;
return
;
}
}
if
(
ptr
+
4
>
end
)
if
(
ptr
+
4
>
end
)
{
{
RecvErr
(
"No proto key"
,
strip_info
);
RecvErr
(
"No proto key"
,
strip_info
);
return
;
return
;
}
}
...
@@ -2259,22 +2237,19 @@ static void process_message(struct strip *strip_info)
...
@@ -2259,22 +2237,19 @@ static void process_message(struct strip *strip_info)
key
.
c
[
3
]
=
*
ptr
++
;
key
.
c
[
3
]
=
*
ptr
++
;
/* If we're using checksums, verify the checksum at the end of the packet */
/* If we're using checksums, verify the checksum at the end of the packet */
if
(
strip_info
->
firmware_level
>=
ChecksummedMessages
)
if
(
strip_info
->
firmware_level
>=
ChecksummedMessages
)
{
{
end
-=
4
;
/* Chop the last four bytes off the packet (they're the checksum) */
end
-=
4
;
/* Chop the last four bytes off the packet (they're the checksum) */
if
(
ptr
>
end
)
if
(
ptr
>
end
)
{
{
RecvErr
(
"Missing Checksum"
,
strip_info
);
RecvErr
(
"Missing Checksum"
,
strip_info
);
return
;
return
;
}
}
if
(
!
verify_checksum
(
strip_info
))
if
(
!
verify_checksum
(
strip_info
))
{
{
RecvErr
(
"Bad Checksum"
,
strip_info
);
RecvErr
(
"Bad Checksum"
,
strip_info
);
return
;
return
;
}
}
}
}
/*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);
*/
/*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);
*/
/*
/*
* Fill in (pseudo) source and destination addresses in the packet.
* Fill in (pseudo) source and destination addresses in the packet.
...
@@ -2302,16 +2277,24 @@ static void process_message(struct strip *strip_info)
...
@@ -2302,16 +2277,24 @@ static void process_message(struct strip *strip_info)
process_Info
(
strip_info
,
ptr
,
end
);
process_Info
(
strip_info
,
ptr
,
end
);
}
else
if
(
key
.
l
==
ERR_Key
.
l
)
{
}
else
if
(
key
.
l
==
ERR_Key
.
l
)
{
strip_info
->
rx_ebytes
+=
(
end
-
ptr
);
strip_info
->
rx_ebytes
+=
(
end
-
ptr
);
RecvErr_Message
(
strip_info
,
sendername
,
ptr
,
end
-
ptr
);
RecvErr_Message
(
strip_info
,
sendername
,
ptr
,
end
-
ptr
);
}
else
RecvErr
(
"Unrecognized protocol key"
,
strip_info
);
}
else
RecvErr
(
"Unrecognized protocol key"
,
strip_info
);
#else
#else
if
(
key
.
l
==
SIP0Key
.
l
)
process_IP_packet
(
strip_info
,
&
header
,
ptr
,
end
);
if
(
key
.
l
==
SIP0Key
.
l
)
else
if
(
key
.
l
==
ARP0Key
.
l
)
process_ARP_packet
(
strip_info
,
&
header
,
ptr
,
end
);
process_IP_packet
(
strip_info
,
&
header
,
ptr
,
end
);
else
if
(
key
.
l
==
ATR_Key
.
l
)
process_AT_response
(
strip_info
,
ptr
,
end
);
else
if
(
key
.
l
==
ARP0Key
.
l
)
else
if
(
key
.
l
==
ACK_Key
.
l
)
process_ACK
(
strip_info
,
ptr
,
end
);
process_ARP_packet
(
strip_info
,
&
header
,
ptr
,
end
);
else
if
(
key
.
l
==
INF_Key
.
l
)
process_Info
(
strip_info
,
ptr
,
end
);
else
if
(
key
.
l
==
ATR_Key
.
l
)
else
if
(
key
.
l
==
ERR_Key
.
l
)
RecvErr_Message
(
strip_info
,
sendername
,
ptr
,
end
-
ptr
);
process_AT_response
(
strip_info
,
ptr
,
end
);
else
RecvErr
(
"Unrecognized protocol key"
,
strip_info
);
else
if
(
key
.
l
==
ACK_Key
.
l
)
process_ACK
(
strip_info
,
ptr
,
end
);
else
if
(
key
.
l
==
INF_Key
.
l
)
process_Info
(
strip_info
,
ptr
,
end
);
else
if
(
key
.
l
==
ERR_Key
.
l
)
RecvErr_Message
(
strip_info
,
sendername
,
ptr
,
end
-
ptr
);
else
RecvErr
(
"Unrecognized protocol key"
,
strip_info
);
#endif
#endif
}
}
...
@@ -2327,16 +2310,19 @@ static void process_message(struct strip *strip_info)
...
@@ -2327,16 +2310,19 @@ static void process_message(struct strip *strip_info)
* and sent on to some IP layer for further processing.
* and sent on to some IP layer for further processing.
*/
*/
static
void
static
void
strip_receive_buf
(
struct
tty_struct
*
tty
,
const
unsigned
char
*
cp
,
strip_receive_buf
(
struct
tty_struct
*
tty
,
const
unsigned
char
*
cp
,
char
*
fp
,
int
count
)
char
*
fp
,
int
count
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)
tty
->
disc_data
;
struct
strip
*
strip_info
=
(
struct
strip
*
)
tty
->
disc_data
;
const
unsigned
char
*
end
=
cp
+
count
;
const
unsigned
char
*
end
=
cp
+
count
;
unsigned
long
flags
;
if
(
!
strip_info
||
strip_info
->
magic
!=
STRIP_MAGIC
if
(
!
strip_info
||
strip_info
->
magic
!=
STRIP_MAGIC
||
!
netif_running
(
&
strip_info
->
dev
))
||
!
netif_running
(
&
strip_info
->
dev
))
return
;
return
;
spin_lock_irqsave
(
&
strip_lock
,
flags
);
/* Argh! mtu change time! - costs us the packet part received at the change */
/* Argh! mtu change time! - costs us the packet part received at the change */
if
(
strip_info
->
mtu
!=
strip_info
->
dev
.
mtu
)
if
(
strip_info
->
mtu
!=
strip_info
->
dev
.
mtu
)
strip_changedmtu
(
strip_info
);
strip_changedmtu
(
strip_info
);
...
@@ -2345,7 +2331,8 @@ strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int
...
@@ -2345,7 +2331,8 @@ strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int
{
{
struct timeval tv;
struct timeval tv;
do_gettimeofday(&tv);
do_gettimeofday(&tv);
printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %02d.%06d\n",
printk(KERN_INFO
"**** strip_receive_buf: %3d bytes at %02d.%06d\n",
count, tv.tv_sec % 100, tv.tv_usec);
count, tv.tv_sec % 100, tv.tv_usec);
}
}
#endif
#endif
...
@@ -2355,55 +2342,66 @@ strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int
...
@@ -2355,55 +2342,66 @@ strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int
#endif
#endif
/* Read the characters out of the buffer */
/* Read the characters out of the buffer */
while
(
cp
<
end
)
while
(
cp
<
end
)
{
{
if
(
fp
&&
*
fp
)
if
(
fp
&&
*
fp
)
printk
(
KERN_INFO
"%s: %s on serial port
\n
"
,
strip_info
->
dev
.
name
,
TTYERROR
(
*
fp
));
printk
(
KERN_INFO
"%s: %s on serial port
\n
"
,
if
(
fp
&&
*
fp
++
&&
!
strip_info
->
discard
)
/* If there's a serial error, record it */
strip_info
->
dev
.
name
,
TTYERROR
(
*
fp
));
{
if
(
fp
&&
*
fp
++
&&
!
strip_info
->
discard
)
{
/* If there's a serial error, record it */
/* If we have some characters in the buffer, discard them */
/* If we have some characters in the buffer, discard them */
strip_info
->
discard
=
strip_info
->
sx_count
;
strip_info
->
discard
=
strip_info
->
sx_count
;
strip_info
->
rx_errors
++
;
strip_info
->
rx_errors
++
;
}
}
/* Leading control characters (CR, NL, Tab, etc.) are ignored */
/* Leading control characters (CR, NL, Tab, etc.) are ignored */
if
(
strip_info
->
sx_count
>
0
||
*
cp
>=
' '
)
if
(
strip_info
->
sx_count
>
0
||
*
cp
>=
' '
)
{
{
if
(
*
cp
==
0x0D
)
{
/* If end of packet, decide what to do with it */
if
(
*
cp
==
0x0D
)
/* If end of packet, decide what to do with it */
{
if
(
strip_info
->
sx_count
>
3000
)
if
(
strip_info
->
sx_count
>
3000
)
printk
(
KERN_INFO
"%s: Cut a %d byte packet (%d bytes remaining)%s
\n
"
,
printk
(
KERN_INFO
strip_info
->
dev
.
name
,
strip_info
->
sx_count
,
end
-
cp
-
1
,
"%s: Cut a %d byte packet (%d bytes remaining)%s
\n
"
,
strip_info
->
discard
?
" (discarded)"
:
""
);
strip_info
->
dev
.
name
,
if
(
strip_info
->
sx_count
>
strip_info
->
sx_size
)
strip_info
->
sx_count
,
{
end
-
cp
-
1
,
strip_info
->
discard
?
" (discarded)"
:
""
);
if
(
strip_info
->
sx_count
>
strip_info
->
sx_size
)
{
strip_info
->
rx_over_errors
++
;
strip_info
->
rx_over_errors
++
;
printk
(
KERN_INFO
"%s: sx_buff overflow (%d bytes total)
\n
"
,
printk
(
KERN_INFO
strip_info
->
dev
.
name
,
strip_info
->
sx_count
);
"%s: sx_buff overflow (%d bytes total)
\n
"
,
}
strip_info
->
dev
.
name
,
else
if
(
strip_info
->
discard
)
strip_info
->
sx_count
);
printk
(
KERN_INFO
"%s: Discarding bad packet (%d/%d)
\n
"
,
}
else
if
(
strip_info
->
discard
)
strip_info
->
dev
.
name
,
strip_info
->
discard
,
strip_info
->
sx_count
);
printk
(
KERN_INFO
else
process_message
(
strip_info
);
"%s: Discarding bad packet (%d/%d)
\n
"
,
strip_info
->
dev
.
name
,
strip_info
->
discard
,
strip_info
->
sx_count
);
else
process_message
(
strip_info
);
strip_info
->
discard
=
0
;
strip_info
->
discard
=
0
;
strip_info
->
sx_count
=
0
;
strip_info
->
sx_count
=
0
;
}
}
else
{
else
{
/* Make sure we have space in the buffer */
/* Make sure we have space in the buffer */
if
(
strip_info
->
sx_count
<
strip_info
->
sx_size
)
if
(
strip_info
->
sx_count
<
strip_info
->
sx_buff
[
strip_info
->
sx_count
]
=
*
cp
;
strip_info
->
sx_size
)
strip_info
->
sx_buff
[
strip_info
->
sx_count
]
=
*
cp
;
strip_info
->
sx_count
++
;
strip_info
->
sx_count
++
;
}
}
}
}
cp
++
;
cp
++
;
}
}
spin_unlock_irqrestore
(
&
strip_lock
,
flags
);
}
}
/************************************************************************/
/************************************************************************/
/* General control routines */
/* General control routines */
static
int
set_mac_address
(
struct
strip
*
strip_info
,
MetricomAddress
*
addr
)
static
int
set_mac_address
(
struct
strip
*
strip_info
,
MetricomAddress
*
addr
)
{
{
/*
/*
* We're using a manually specified address if the address is set
* We're using a manually specified address if the address is set
...
@@ -2411,26 +2409,30 @@ static int set_mac_address(struct strip *strip_info, MetricomAddress *addr)
...
@@ -2411,26 +2409,30 @@ static int set_mac_address(struct strip *strip_info, MetricomAddress *addr)
* disables manual mode and goes back to automatic address determination
* disables manual mode and goes back to automatic address determination
* (tracking the true address that the radio has).
* (tracking the true address that the radio has).
*/
*/
strip_info
->
manual_dev_addr
=
memcmp
(
addr
->
c
,
broadcast_address
.
c
,
sizeof
(
broadcast_address
));
strip_info
->
manual_dev_addr
=
memcmp
(
addr
->
c
,
broadcast_address
.
c
,
sizeof
(
broadcast_address
));
if
(
strip_info
->
manual_dev_addr
)
if
(
strip_info
->
manual_dev_addr
)
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
*
addr
;
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
*
addr
;
else
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
strip_info
->
true_dev_addr
;
else
*
(
MetricomAddress
*
)
strip_info
->
dev
.
dev_addr
=
strip_info
->
true_dev_addr
;
return
0
;
return
0
;
}
}
static
int
dev_set_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
static
int
dev_set_mac_address
(
struct
net_device
*
dev
,
void
*
addr
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
struct
sockaddr
*
sa
=
addr
;
struct
sockaddr
*
sa
=
addr
;
printk
(
KERN_INFO
"%s: strip_set_dev_mac_address called
\n
"
,
dev
->
name
);
printk
(
KERN_INFO
"%s: strip_set_dev_mac_address called
\n
"
,
dev
->
name
);
set_mac_address
(
strip_info
,
(
MetricomAddress
*
)
sa
->
sa_data
);
set_mac_address
(
strip_info
,
(
MetricomAddress
*
)
sa
->
sa_data
);
return
0
;
return
0
;
}
}
static
struct
net_device_stats
*
strip_get_stats
(
struct
net_device
*
dev
)
static
struct
net_device_stats
*
strip_get_stats
(
struct
net_device
*
dev
)
{
{
static
struct
net_device_stats
stats
;
static
struct
net_device_stats
stats
;
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
memset
(
&
stats
,
0
,
sizeof
(
struct
net_device_stats
));
memset
(
&
stats
,
0
,
sizeof
(
struct
net_device_stats
));
...
@@ -2441,7 +2443,7 @@ static struct net_device_stats *strip_get_stats(struct net_device *dev)
...
@@ -2441,7 +2443,7 @@ static struct net_device_stats *strip_get_stats(struct net_device *dev)
stats
.
tx_errors
=
strip_info
->
tx_errors
;
stats
.
tx_errors
=
strip_info
->
tx_errors
;
stats
.
rx_errors
=
strip_info
->
rx_errors
;
stats
.
rx_errors
=
strip_info
->
rx_errors
;
stats
.
rx_over_errors
=
strip_info
->
rx_over_errors
;
stats
.
rx_over_errors
=
strip_info
->
rx_over_errors
;
return
(
&
stats
);
return
(
&
stats
);
}
}
...
@@ -2474,16 +2476,13 @@ static struct net_device_stats *strip_get_stats(struct net_device *dev)
...
@@ -2474,16 +2476,13 @@ static struct net_device_stats *strip_get_stats(struct net_device *dev)
static
int
strip_open_low
(
struct
net_device
*
dev
)
static
int
strip_open_low
(
struct
net_device
*
dev
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
#if 0
struct in_device *in_dev = dev->ip_ptr;
#endif
if
(
strip_info
->
tty
==
NULL
)
if
(
strip_info
->
tty
==
NULL
)
return
(
-
ENODEV
);
return
(
-
ENODEV
);
if
(
!
allocate_buffers
(
strip_info
))
if
(
!
allocate_buffers
(
strip_info
))
return
(
-
ENOMEM
);
return
(
-
ENOMEM
);
strip_info
->
sx_count
=
0
;
strip_info
->
sx_count
=
0
;
strip_info
->
tx_left
=
0
;
strip_info
->
tx_left
=
0
;
...
@@ -2494,23 +2493,13 @@ static int strip_open_low(struct net_device *dev)
...
@@ -2494,23 +2493,13 @@ static int strip_open_low(struct net_device *dev)
strip_info
->
next_command
=
CompatibilityCommand
;
strip_info
->
next_command
=
CompatibilityCommand
;
strip_info
->
user_baud
=
get_baud
(
strip_info
->
tty
);
strip_info
->
user_baud
=
get_baud
(
strip_info
->
tty
);
#if 0
printk
(
KERN_INFO
"%s: Initializing Radio.
\n
"
,
/*
strip_info
->
dev
.
name
);
* Needed because address '0' is special
*
* --ANK Needed it or not needed, it does not matter at all.
* Make it at user level, guys.
*/
if (in_dev->ifa_list->ifa_address == 0)
in_dev->ifa_list->ifa_address = ntohl(0xC0A80001);
#endif
printk
(
KERN_INFO
"%s: Initializing Radio.
\n
"
,
strip_info
->
dev
.
name
);
ResetRadio
(
strip_info
);
ResetRadio
(
strip_info
);
strip_info
->
idle_timer
.
expires
=
jiffies
+
1
*
HZ
;
strip_info
->
idle_timer
.
expires
=
jiffies
+
1
*
HZ
;
add_timer
(
&
strip_info
->
idle_timer
);
add_timer
(
&
strip_info
->
idle_timer
);
netif_wake_queue
(
dev
);
netif_wake_queue
(
dev
);
return
(
0
);
return
(
0
);
}
}
...
@@ -2520,7 +2509,7 @@ static int strip_open_low(struct net_device *dev)
...
@@ -2520,7 +2509,7 @@ static int strip_open_low(struct net_device *dev)
static
int
strip_close_low
(
struct
net_device
*
dev
)
static
int
strip_close_low
(
struct
net_device
*
dev
)
{
{
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
struct
strip
*
strip_info
=
(
struct
strip
*
)
(
dev
->
priv
);
if
(
strip_info
->
tty
==
NULL
)
if
(
strip_info
->
tty
==
NULL
)
return
-
EBUSY
;
return
-
EBUSY
;
...
@@ -2531,18 +2520,15 @@ static int strip_close_low(struct net_device *dev)
...
@@ -2531,18 +2520,15 @@ static int strip_close_low(struct net_device *dev)
/*
/*
* Free all STRIP frame buffers.
* Free all STRIP frame buffers.
*/
*/
if
(
strip_info
->
rx_buff
)
if
(
strip_info
->
rx_buff
)
{
{
kfree
(
strip_info
->
rx_buff
);
kfree
(
strip_info
->
rx_buff
);
strip_info
->
rx_buff
=
NULL
;
strip_info
->
rx_buff
=
NULL
;
}
}
if
(
strip_info
->
sx_buff
)
if
(
strip_info
->
sx_buff
)
{
{
kfree
(
strip_info
->
sx_buff
);
kfree
(
strip_info
->
sx_buff
);
strip_info
->
sx_buff
=
NULL
;
strip_info
->
sx_buff
=
NULL
;
}
}
if
(
strip_info
->
tx_buff
)
if
(
strip_info
->
tx_buff
)
{
{
kfree
(
strip_info
->
tx_buff
);
kfree
(
strip_info
->
tx_buff
);
strip_info
->
tx_buff
=
NULL
;
strip_info
->
tx_buff
=
NULL
;
}
}
...
@@ -2573,7 +2559,7 @@ static int strip_dev_init(struct net_device *dev)
...
@@ -2573,7 +2559,7 @@ static int strip_dev_init(struct net_device *dev)
* dev->priv Already holds a pointer to our struct strip
* dev->priv Already holds a pointer to our struct strip
*/
*/
*
(
MetricomAddress
*
)
&
dev
->
broadcast
=
broadcast_address
;
*
(
MetricomAddress
*
)
&
dev
->
broadcast
=
broadcast_address
;
dev
->
dev_addr
[
0
]
=
0
;
dev
->
dev_addr
[
0
]
=
0
;
dev
->
addr_len
=
sizeof
(
MetricomAddress
);
dev
->
addr_len
=
sizeof
(
MetricomAddress
);
...
@@ -2616,7 +2602,7 @@ static struct strip *strip_alloc(void)
...
@@ -2616,7 +2602,7 @@ static struct strip *strip_alloc(void)
kmalloc
(
sizeof
(
struct
strip
),
GFP_KERNEL
);
kmalloc
(
sizeof
(
struct
strip
),
GFP_KERNEL
);
if
(
!
strip_info
)
if
(
!
strip_info
)
return
(
NULL
);
/* If no more memory, return */
return
NULL
;
/* If no more memory, return */
/*
/*
* Clear the allocated memory
* Clear the allocated memory
...
@@ -2630,8 +2616,7 @@ static struct strip *strip_alloc(void)
...
@@ -2630,8 +2616,7 @@ static struct strip *strip_alloc(void)
* going to be)
* going to be)
*/
*/
while
(
*
s
&&
(
*
s
)
->
dev
.
base_addr
==
channel_id
)
while
(
*
s
&&
(
*
s
)
->
dev
.
base_addr
==
channel_id
)
{
{
channel_id
++
;
channel_id
++
;
s
=
&
(
*
s
)
->
next
;
s
=
&
(
*
s
)
->
next
;
}
}
...
@@ -2652,17 +2637,17 @@ static struct strip *strip_alloc(void)
...
@@ -2652,17 +2637,17 @@ static struct strip *strip_alloc(void)
strip_info
->
gratuitous_arp
=
jiffies
+
LongTime
;
strip_info
->
gratuitous_arp
=
jiffies
+
LongTime
;
strip_info
->
arp_interval
=
0
;
strip_info
->
arp_interval
=
0
;
init_timer
(
&
strip_info
->
idle_timer
);
init_timer
(
&
strip_info
->
idle_timer
);
strip_info
->
idle_timer
.
data
=
(
long
)
&
strip_info
->
dev
;
strip_info
->
idle_timer
.
data
=
(
long
)
&
strip_info
->
dev
;
strip_info
->
idle_timer
.
function
=
strip_IdleTask
;
strip_info
->
idle_timer
.
function
=
strip_IdleTask
;
/* Note: strip_info->if_name is currently 8 characters long */
/* Note: strip_info->if_name is currently 8 characters long */
sprintf
(
strip_info
->
dev
.
name
,
"st%d"
,
channel_id
);
sprintf
(
strip_info
->
dev
.
name
,
"st%d"
,
channel_id
);
strip_info
->
dev
.
base_addr
=
channel_id
;
strip_info
->
dev
.
base_addr
=
channel_id
;
strip_info
->
dev
.
priv
=
(
void
*
)
strip_info
;
strip_info
->
dev
.
priv
=
(
void
*
)
strip_info
;
strip_info
->
dev
.
next
=
NULL
;
strip_info
->
dev
.
next
=
NULL
;
strip_info
->
dev
.
init
=
strip_dev_init
;
strip_info
->
dev
.
init
=
strip_dev_init
;
return
(
strip_info
)
;
return
strip_info
;
}
}
/*
/*
...
@@ -2695,8 +2680,7 @@ static int strip_open(struct tty_struct *tty)
...
@@ -2695,8 +2680,7 @@ static int strip_open(struct tty_struct *tty)
* strip_dev_init() will be called as a side-effect
* strip_dev_init() will be called as a side-effect
*/
*/
if
(
register_netdev
(
&
strip_info
->
dev
)
!=
0
)
if
(
register_netdev
(
&
strip_info
->
dev
)
!=
0
)
{
{
printk
(
KERN_ERR
"strip: register_netdev() failed.
\n
"
);
printk
(
KERN_ERR
"strip: register_netdev() failed.
\n
"
);
strip_free
(
strip_info
);
strip_free
(
strip_info
);
return
-
ENFILE
;
return
-
ENFILE
;
...
@@ -2719,18 +2703,19 @@ static int strip_open(struct tty_struct *tty)
...
@@ -2719,18 +2703,19 @@ static int strip_open(struct tty_struct *tty)
* Set tty options
* Set tty options
*/
*/
tty
->
termios
->
c_iflag
|=
IGNBRK
|
IGNPAR
;
/* Ignore breaks and parity errors. */
tty
->
termios
->
c_iflag
|=
IGNBRK
|
IGNPAR
;
/* Ignore breaks and parity errors. */
tty
->
termios
->
c_cflag
|=
CLOCAL
;
/* Ignore modem control signals. */
tty
->
termios
->
c_cflag
|=
CLOCAL
;
/* Ignore modem control signals. */
tty
->
termios
->
c_cflag
&=
~
HUPCL
;
/* Don't close on hup */
tty
->
termios
->
c_cflag
&=
~
HUPCL
;
/* Don't close on hup */
MOD_INC_USE_COUNT
;
MOD_INC_USE_COUNT
;
printk
(
KERN_INFO
"STRIP: device
\"
%s
\"
activated
\n
"
,
strip_info
->
dev
.
name
);
printk
(
KERN_INFO
"STRIP: device
\"
%s
\"
activated
\n
"
,
strip_info
->
dev
.
name
);
/*
/*
* Done. We have linked the TTY line to a channel.
* Done. We have linked the TTY line to a channel.
*/
*/
return
(
strip_info
->
dev
.
base_addr
);
return
(
strip_info
->
dev
.
base_addr
);
}
}
/*
/*
...
@@ -2755,7 +2740,8 @@ static void strip_close(struct tty_struct *tty)
...
@@ -2755,7 +2740,8 @@ static void strip_close(struct tty_struct *tty)
tty
->
disc_data
=
0
;
tty
->
disc_data
=
0
;
strip_info
->
tty
=
NULL
;
strip_info
->
tty
=
NULL
;
printk
(
KERN_INFO
"STRIP: device
\"
%s
\"
closed down
\n
"
,
strip_info
->
dev
.
name
);
printk
(
KERN_INFO
"STRIP: device
\"
%s
\"
closed down
\n
"
,
strip_info
->
dev
.
name
);
strip_free
(
strip_info
);
strip_free
(
strip_info
);
tty
->
disc_data
=
NULL
;
tty
->
disc_data
=
NULL
;
MOD_DEC_USE_COUNT
;
MOD_DEC_USE_COUNT
;
...
@@ -2777,20 +2763,18 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
...
@@ -2777,20 +2763,18 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
if
(
!
strip_info
||
strip_info
->
magic
!=
STRIP_MAGIC
)
if
(
!
strip_info
||
strip_info
->
magic
!=
STRIP_MAGIC
)
return
-
EINVAL
;
return
-
EINVAL
;
switch
(
cmd
)
switch
(
cmd
)
{
{
case
SIOCGIFNAME
:
case
SIOCGIFNAME
:
return
copy_to_user
((
void
*
)
arg
,
strip_info
->
dev
.
name
,
if
(
copy_to_user
((
void
*
)
arg
,
strip_info
->
dev
.
name
,
strlen
(
strip_info
->
dev
.
name
)
+
1
))
strlen
(
strip_info
->
dev
.
name
)
+
1
)
?
return
-
EFAULT
;
-
EFAULT
:
0
;
break
;
break
;
case
SIOCSIFHWADDR
:
case
SIOCSIFHWADDR
:
{
{
MetricomAddress
addr
;
MetricomAddress
addr
;
printk
(
KERN_INFO
"%s: SIOCSIFHWADDR
\n
"
,
strip_info
->
dev
.
name
);
//
printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev.name);
return
copy_from_user
(
&
addr
,
(
void
*
)
arg
,
sizeof
(
MetricomAddress
))
?
if
(
copy_from_user
(
&
addr
,
(
void
*
)
arg
,
sizeof
(
MetricomAddress
)))
-
EFAULT
:
set_mac_address
(
strip_info
,
&
addr
)
;
return
-
EFAULT
;
break
;
return
set_mac_address
(
strip_info
,
&
addr
)
;
}
}
/*
/*
* Allow stty to read, but not set, the serial port
* Allow stty to read, but not set, the serial port
...
@@ -2798,13 +2782,13 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
...
@@ -2798,13 +2782,13 @@ static int strip_ioctl(struct tty_struct *tty, struct file *file,
case
TCGETS
:
case
TCGETS
:
case
TCGETA
:
case
TCGETA
:
return
n_tty_ioctl
(
tty
,
(
struct
file
*
)
file
,
cmd
,
return
n_tty_ioctl
(
tty
,
(
struct
file
*
)
file
,
cmd
,
(
unsigned
long
)
arg
);
(
unsigned
long
)
arg
);
break
;
break
;
default:
default:
return
-
ENOIOCTLCMD
;
return
-
ENOIOCTLCMD
;
break
;
break
;
}
}
return
0
;
}
}
...
@@ -2828,7 +2812,8 @@ static struct tty_ldisc strip_ldisc = {
...
@@ -2828,7 +2812,8 @@ static struct tty_ldisc strip_ldisc = {
* STRIP driver
* STRIP driver
*/
*/
static
char
signon
[]
__initdata
=
KERN_INFO
"STRIP: Version %s (unlimited channels)
\n
"
;
static
char
signon
[]
__initdata
=
KERN_INFO
"STRIP: Version %s (unlimited channels)
\n
"
;
static
int
__init
strip_init_driver
(
void
)
static
int
__init
strip_init_driver
(
void
)
{
{
...
@@ -2836,11 +2821,14 @@ static int __init strip_init_driver(void)
...
@@ -2836,11 +2821,14 @@ static int __init strip_init_driver(void)
printk
(
signon
,
StripVersion
);
printk
(
signon
,
StripVersion
);
spin_lock_init
(
&
strip_lock
);
/*
/*
* Fill in our line protocol discipline, and register it
* Fill in our line protocol discipline, and register it
*/
*/
if
((
status
=
tty_register_ldisc
(
N_STRIP
,
&
strip_ldisc
)))
if
((
status
=
tty_register_ldisc
(
N_STRIP
,
&
strip_ldisc
)))
printk
(
KERN_ERR
"STRIP: can't register line discipline (err = %d)
\n
"
,
status
);
printk
(
KERN_ERR
"STRIP: can't register line discipline (err = %d)
\n
"
,
status
);
/*
/*
* Register the status file with /proc
* Register the status file with /proc
...
@@ -2849,9 +2837,11 @@ static int __init strip_init_driver(void)
...
@@ -2849,9 +2837,11 @@ static int __init strip_init_driver(void)
return
status
;
return
status
;
}
}
module_init
(
strip_init_driver
);
module_init
(
strip_init_driver
);
static
const
char
signoff
[]
__exitdata
=
KERN_INFO
"STRIP: Module Unloaded
\n
"
;
static
const
char
signoff
[]
__exitdata
=
KERN_INFO
"STRIP: Module Unloaded
\n
"
;
static
void
__exit
strip_exit_driver
(
void
)
static
void
__exit
strip_exit_driver
(
void
)
{
{
...
@@ -2867,6 +2857,7 @@ static void __exit strip_exit_driver(void)
...
@@ -2867,6 +2857,7 @@ static void __exit strip_exit_driver(void)
printk
(
signoff
);
printk
(
signoff
);
}
}
module_exit
(
strip_exit_driver
);
module_exit
(
strip_exit_driver
);
MODULE_AUTHOR
(
"Stuart Cheshire <cheshire@cs.stanford.edu>"
);
MODULE_AUTHOR
(
"Stuart Cheshire <cheshire@cs.stanford.edu>"
);
...
@@ -2874,4 +2865,3 @@ MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver");
...
@@ -2874,4 +2865,3 @@ MODULE_DESCRIPTION("Starmode Radio IP (STRIP) Device Driver");
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_LICENSE
(
"Dual BSD/GPL"
);
MODULE_SUPPORTED_DEVICE
(
"Starmode Radio IP (STRIP) modem"
);
MODULE_SUPPORTED_DEVICE
(
"Starmode Radio IP (STRIP) modem"
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment