forked from pandax381/microps
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathether.c
More file actions
127 lines (114 loc) · 3.41 KB
/
ether.c
File metadata and controls
127 lines (114 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "util.h"
#include "net.h"
#include "ether.h"
struct ether_hdr {
uint8_t dst[ETHER_ADDR_LEN];
uint8_t src[ETHER_ADDR_LEN];
uint16_t type;
};
const uint8_t ETHER_ADDR_ANY[ETHER_ADDR_LEN] = {"\x00\x00\x00\x00\x00\x00"};
const uint8_t ETHER_ADDR_BROADCAST[ETHER_ADDR_LEN] = {"\xff\xff\xff\xff\xff\xff"};
int
ether_addr_pton(const char *p, uint8_t *n)
{
int index;
char *ep;
long val;
if (!p || !n) {
return -1;
}
for (index = 0; index < ETHER_ADDR_LEN; index++) {
val = strtol(p, &ep, 16);
if (ep == p || val < 0 || val > 0xff || (index < ETHER_ADDR_LEN - 1 && *ep != ':')) {
break;
}
n[index] = (uint8_t)val;
p = ep + 1;
}
if (index != ETHER_ADDR_LEN || *ep != '\0') {
return -1;
}
return 0;
}
char *
ether_addr_ntop(const uint8_t *n, char *p, size_t size)
{
if (!n || !p) {
return NULL;
}
snprintf(p, size, "%02x:%02x:%02x:%02x:%02x:%02x", n[0], n[1], n[2], n[3], n[4], n[5]);
return p;
}
static void
ether_dump(const uint8_t *frame, size_t flen)
{
struct ether_hdr *hdr;
char addr[ETHER_ADDR_STR_LEN];
hdr = (struct ether_hdr *)frame;
flockfile(stderr);
fprintf(stderr, " src: %s\n", ether_addr_ntop(hdr->src, addr, sizeof(addr)));
fprintf(stderr, " dst: %s\n", ether_addr_ntop(hdr->dst, addr, sizeof(addr)));
fprintf(stderr, " type: 0x%04x\n", ntoh16(hdr->type));
#ifdef HEXDUMP
hexdump(stderr, frame, flen);
#endif
funlockfile(stderr);
}
int
ether_transmit_helper(struct net_device *dev, uint16_t type, const uint8_t *data, size_t len, const void *dst, ether_transmit_func_t callback)
{
uint8_t frame[ETHER_FRAME_SIZE_MAX] = {};
struct ether_hdr *hdr;
size_t flen, pad = 0;
hdr = (struct ether_hdr *)frame;
memcpy(hdr->dst, dst, ETHER_ADDR_LEN);
memcpy(hdr->src, dev->addr, ETHER_ADDR_LEN);
hdr->type = hton16(type);
memcpy(hdr+1, data, len);
if (len < ETHER_PAYLOAD_SIZE_MIN) {
pad = ETHER_PAYLOAD_SIZE_MIN - len;
}
flen = sizeof(*hdr) + len + pad;
debugf("dev=%s, type=0x%04x, len=%zu", dev->name, type, flen);
ether_dump(frame, flen);
return callback(dev, frame, flen) == (ssize_t)flen ? 0 : -1;
}
int
ether_input_helper(struct net_device *dev, ether_input_func_t callback)
{
uint8_t frame[ETHER_FRAME_SIZE_MAX];
ssize_t flen;
struct ether_hdr *hdr;
uint16_t type;
flen = callback(dev, frame, sizeof(frame));
if (flen < (ssize_t)sizeof(*hdr)) {
errorf("too short");
return -1;
}
hdr = (struct ether_hdr *)frame;
if (memcmp(dev->addr, hdr->dst, ETHER_ADDR_LEN) != 0) {
if (memcmp(ETHER_ADDR_BROADCAST, hdr->dst, ETHER_ADDR_LEN) != 0) {
return -1;
}
}
type = ntoh16(hdr->type);
debugf("dev=%s, type=0x%04x, len=%zd", dev->name, type, flen);
ether_dump(frame, flen);
return net_input_handler(type, (uint8_t *)(hdr+1), flen - sizeof(*hdr), dev);
}
void
ether_setup_helper(struct net_device *dev)
{
dev->type = NET_DEVICE_TYPE_ETHERNET;
dev->mtu = ETHER_PAYLOAD_SIZE_MAX;
dev->flags = (NET_DEVICE_FLAG_BROADCAST | NET_DEVICE_FLAG_NEED_ARP);
dev->hlen = ETHER_HDR_SIZE;
dev->alen = ETHER_ADDR_LEN;
memcpy(dev->broadcast, ETHER_ADDR_BROADCAST, ETHER_ADDR_LEN);
}