AquilaOS documentation
How it works, and its code
Loading...
Searching...
No Matches
ifioctl.c
Go to the documentation of this file.
1
8
9#include <core/system.h>
10#include <core/string.h>
11#include <net/byteorder.h>
12#include <net/inet.h>
13#include <sys/proc.h>
14#include <sys/sched.h>
15#include <sys/uaccess.h>
16
17#include <aquila/errno.h>
18#include <aquila/if.h>
19#include <aquila/in.h>
20#include <aquila/ioctl.h>
21#include <aquila/route.h>
22
24static int netif_index(struct netif *netif)
25{
26 int i = 1;
27
28 for (struct netif *n = netifs; n && n != netif; n = n->next)
29 ++i;
30
31 return i;
32}
33
35static void ifaddr_put(struct sockaddr *a, uint32_t ip)
36{
37 struct sockaddr_in *sin = (struct sockaddr_in *) a;
38
39 memset(a, 0, sizeof(*a));
40 sin->sin_family = AF_INET;
41 sin->sin_addr.s_addr = ip;
42}
43
46static int ifaddr_get(const struct sockaddr *a, uint32_t *ip)
47{
48 const struct sockaddr_in *sin = (const struct sockaddr_in *) a;
49
50 if (sin->sin_family != AF_INET)
51 return -EAFNOSUPPORT;
52
53 *ip = sin->sin_addr.s_addr;
54 return 0;
55}
56
60static int ifconf(struct ifconf *uifc)
61{
62 struct ifconf ifc;
63
64 if (copyin(&ifc, uifc, sizeof(ifc)))
65 return -EFAULT;
66
67 int n = 0;
68
69 for (struct netif *netif = netifs; netif; netif = netif->next)
70 ++n;
71
72 if (!ifc.ifc_buf) {
73 ifc.ifc_len = n * sizeof(struct ifreq);
74 return copyout(uifc, &ifc, sizeof(ifc));
75 }
76
77 if (ifc.ifc_len < 0)
78 return -EINVAL;
79
80 int len = 0;
81
82 /* make each entry here, then copy it out */
83 for (struct netif *netif = netifs; netif; netif = netif->next) {
84 if (len + (int) sizeof(struct ifreq) > ifc.ifc_len)
85 break;
86
87 struct ifreq ifr;
88 memset(&ifr, 0, sizeof(ifr));
89 memcpy(ifr.ifr_name, netif->name, sizeof(netif->name));
90 ifaddr_put(&ifr.ifr_addr, netif->ip);
91
92 if (copyout(ifc.ifc_buf + len, &ifr, sizeof(ifr)))
93 return -EFAULT;
94
95 len += sizeof(struct ifreq);
96 }
97
98 ifc.ifc_len = len;
99 return copyout(uifc, &ifc, sizeof(ifc));
100}
101
106static int route(int request, struct rtentry *urt)
107{
108 struct rtentry _rt, *rt = &_rt;
109
110 if (copyin(rt, urt, sizeof(*rt)))
111 return -EFAULT;
112
113 const struct sockaddr_in *dst = (const struct sockaddr_in *) &rt->rt_dst;
114 const struct sockaddr_in *mask = (const struct sockaddr_in *) &rt->rt_genmask;
115 const struct sockaddr_in *gateway = (const struct sockaddr_in *) &rt->rt_gateway;
116
117 if (dst->sin_addr.s_addr || mask->sin_addr.s_addr)
118 return -EINVAL;
119
120 if (request == SIOCDELRT) {
121 for (struct netif *netif = netifs; netif; netif = netif->next)
122 netif->gateway = 0;
123
124 return 0;
125 }
126
127 uint32_t gw = gateway->sin_addr.s_addr;
128
129 if (!(rt->rt_flags & RTF_GATEWAY) || gateway->sin_family != AF_INET || !gw)
130 return -EINVAL;
131
132 for (struct netif *netif = netifs; netif; netif = netif->next) {
133 if (netif->ip && (gw & netif->netmask) == (netif->ip & netif->netmask)) {
134 netif->gateway = gw;
135 return 0;
136 }
137 }
138
139 return -ENETUNREACH;
140}
141
142static int ifreq_request(int request, struct ifreq *ifr);
143
153int inet_ifioctl(int request, void *argp)
154{
155 switch (request) {
156 case SIOCGIFCONF:
157 return ifconf(argp);
158
159 case SIOCADDRT:
160 case SIOCDELRT:
161 if (curproc->uid)
162 return -EPERM;
163
164 return route(request, argp);
165 }
166
167 /* the requests about one interface, named in a struct ifreq: work on
168 * the kernel's copy of it, then copy it back out */
169 struct ifreq ifr;
170
171 switch (request) {
172 case SIOCGIFFLAGS: case SIOCSIFFLAGS:
173 case SIOCGIFADDR: case SIOCSIFADDR:
174 case SIOCGIFNETMASK: case SIOCSIFNETMASK:
175 case SIOCGIFBRDADDR: case SIOCGIFHWADDR:
176 case SIOCGIFMTU: case SIOCGIFINDEX:
177 break;
178 default:
179 return -ENOTTY;
180 }
181
182 if (copyin(&ifr, argp, sizeof(ifr)))
183 return -EFAULT;
184
185 ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
186
187 int err = ifreq_request(request, &ifr);
188 return err ? err : copyout(argp, &ifr, sizeof(ifr));
189}
190
193static int ifreq_request(int request, struct ifreq *ifr)
194{
195 struct netif *netif = netif_find(ifr->ifr_name);
196
197 if (!netif)
198 return -ENODEV;
199
200 int set = request == SIOCSIFFLAGS || request == SIOCSIFADDR || request == SIOCSIFNETMASK;
201
202 if (set && curproc->uid)
203 return -EPERM;
204
205 uint32_t ip;
206 int err;
207
208 switch (request) {
209 case SIOCGIFFLAGS:
210 ifr->ifr_flags = (netif->flags & NETIF_LOOPBACK ? IFF_LOOPBACK : IFF_BROADCAST | IFF_MULTICAST) |
211 (netif->flags & NETIF_UP ? IFF_UP : 0) |
212 (netif->flags & NETIF_RUNNING ? IFF_RUNNING : 0);
213 return 0;
214
215 case SIOCSIFFLAGS:
216 if (ifr->ifr_flags & IFF_UP)
217 netif->flags |= NETIF_UP;
218 else
220 return 0;
221
222 case SIOCGIFADDR:
223 ifaddr_put(&ifr->ifr_addr, netif->ip);
224 return 0;
225
226 case SIOCSIFADDR:
227 if ((err = ifaddr_get(&ifr->ifr_addr, &ip)))
228 return err;
229
230 netif->ip = ip;
231
232 /* a /24 mask until one is set (whatever the address's
233 * class) */
234 if (!netif->netmask)
235 netif->netmask = htonl(0xffffff00);
236
237 return 0;
238
239 case SIOCGIFNETMASK:
240 ifaddr_put(&ifr->ifr_netmask, netif->netmask);
241 return 0;
242
243 case SIOCSIFNETMASK:
244 if ((err = ifaddr_get(&ifr->ifr_netmask, &ip)))
245 return err;
246
247 netif->netmask = ip;
248 return 0;
249
250 case SIOCGIFBRDADDR:
251 ifaddr_put(&ifr->ifr_broadaddr, netif->ip | ~netif->netmask);
252 return 0;
253
254 case SIOCGIFHWADDR:
255 memset(&ifr->ifr_hwaddr, 0, sizeof(ifr->ifr_hwaddr));
256 ifr->ifr_hwaddr.sa_family = netif->flags & NETIF_LOOPBACK ? ARPHRD_LOOPBACK : ARPHRD_ETHER;
257 memcpy(ifr->ifr_hwaddr.sa_data, netif->mac, 6);
258 return 0;
259
260 case SIOCGIFMTU:
261 ifr->ifr_mtu = netif->mtu;
262 return 0;
263
264 case SIOCGIFINDEX:
265 ifr->ifr_ifindex = netif_index(netif);
266 return 0;
267 }
268
269 return -ENOTTY;
270}
#define htonl(x)
Definition byteorder.h:11
static int ifaddr_get(const struct sockaddr *a, uint32_t *ip)
Reads an IPv4 address from a struct sockaddr.
Definition ifioctl.c:46
static int ifconf(struct ifconf *uifc)
Handles SIOCGIFCONF: lists as many interfaces as the buffer has room for, or says how much room is ne...
Definition ifioctl.c:60
static void ifaddr_put(struct sockaddr *a, uint32_t ip)
Writes an IPv4 address into a struct sockaddr.
Definition ifioctl.c:35
static int ifreq_request(int request, struct ifreq *ifr)
Handles a request about one interface, on the kernel's copy of the struct ifreq.
Definition ifioctl.c:193
static int route(int request, struct rtentry *urt)
Handles SIOCADDRT and SIOCDELRT, for the default route only (0.0.0.0/0 through a gateway): the gatewa...
Definition ifioctl.c:106
static int netif_index(struct netif *netif)
Returns an interface's index: its place in the list, from 1.
Definition ifioctl.c:24
int inet_ifioctl(int request, void *argp)
Handles an interface ioctl() request on an AF_INET socket.
Definition ifioctl.c:153
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition libc.c:23
void * memcpy(void *dst, const void *src, size_t n)
Copies n bytes; dst and src must not overlap.
Definition libc.c:11
#define NETIF_LOOPBACK
Definition netif.h:10
#define NETIF_UP
Definition netif.h:8
struct netif * netif_find(const char *name)
Finds an interface by its name.
Definition netif.c:186
#define NETIF_RUNNING
Definition netif.h:9
struct netif * netifs
Definition netif.c:34
#define curproc
Definition sched.h:13
unsigned int uint32_t
Definition stddef.h:22
A network interface (net/netif.c): a device that sends and receives Ethernet frames,...
Definition netif.h:16
int flags
Definition netif.h:20
uint32_t ip
Definition netif.h:24
uint32_t netmask
Definition netif.h:24
char name[8]
Definition netif.h:17
uint32_t gateway
Definition netif.h:24
uint8_t mac[6]
Definition netif.h:18
uint16_t mtu
Definition netif.h:19
struct netif * next
Definition netif.h:37