9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
18 int startNetwork (struct ngadmin *nga)
25 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
31 memset(&ifr, 0, sizeof(struct ifreq));
32 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
34 /* get the interface MAC address */
35 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
37 perror("ioctl(SIOCGIFHWADDR)");
41 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
44 memset(&nga->local, 0, sizeof(struct sockaddr_in));
45 nga->local.sin_family = AF_INET;
46 nga->local.sin_port = htons(CLIENT_PORT);
48 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
55 /* allow broadcasting */
57 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
59 perror("setsockopt(SO_BROADCAST)");
63 /* prevent unicast packets from being routed by setting the TTL to 1 */
65 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
67 perror("setsockopt(IP_TTL)");
76 int setBroadcastType (struct ngadmin *nga, bool value)
82 nga->globalbroad = value;
84 nga->brd.s_addr = (in_addr_t)0;
88 memset(&ifr, 0, sizeof(struct ifreq));
89 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
91 /* get the interface broadcast address */
92 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
94 perror("ioctl(SIOCGIFBRDADDR)");
95 nga->brd.s_addr = (in_addr_t)0;
96 nga->globalbroad = true;
100 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
106 int stopNetwork (struct ngadmin *nga)
108 return close(nga->sock);
112 int forceInterface (struct ngadmin *nga)
118 As described bellow, when you have multiple interfaces, this forces the packet
119 to go to a particular interface.
121 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
123 perror("setsockopt(SO_BINDTODEVICE)");
128 If the switch's IP is not in your network range, for instance because you do
129 not have DHCP enabled or you started the switch after it, this allows to
130 bypass the routing tables and consider every address is directly reachable on
134 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
136 perror("setsockopt(SO_DONTROUTE)");
145 int updateTimeout (struct ngadmin *nga)
150 /* specify receive timeout */
151 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
153 perror("setsockopt(SO_RCVTIMEO)");
162 int sendNgPacket (struct ngadmin *nga, char code, const List *attr)
166 struct sockaddr_in remote;
167 const struct swi_attr *sa = nga->current;
172 np.maxlen = sizeof(buffer);
174 initNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
176 ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
180 memset(&remote, 0, sizeof(struct sockaddr_in));
181 remote.sin_family = AF_INET;
182 remote.sin_port = htons(SWITCH_PORT);
184 /* destination address selection */
185 if (sa != NULL && !nga->keepbroad)
186 remote.sin_addr = sa->nc.ip;
187 else if (nga->globalbroad)
188 remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
190 remote.sin_addr = nga->brd;
192 ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
201 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr)
205 struct sockaddr_in remote;
206 socklen_t slen = sizeof(struct sockaddr_in);
207 const struct swi_attr *sa = nga->current;
215 memset(&remote, 0, sizeof(struct sockaddr_in));
216 remote.sin_family = AF_INET;
223 FD_SET(nga->sock, &fs);
224 select(nga->sock+1, &fs, NULL, NULL, &rem); /* FIXME: non portable */
226 len = recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
234 if (ntohs(remote.sin_port) != SWITCH_PORT ||
235 len < (int)sizeof(struct ng_header) ||
236 !validateNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, nga->seq) ||
237 extractPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports) < 0)
241 *error = np.nh->error;
242 if (attr_error != NULL)
243 *attr_error = ntohs(np.nh->attr);
254 static int checkErrorCode (unsigned char err, unsigned short attr_error)
258 return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
259 case ERROR_INVALID_VALUE:
267 int readRequest (struct ngadmin *nga, List *attr)
271 unsigned short attr_error;
279 /* add end attribute to end */
280 pushBackList(attr, newEmptyAttr(ATTR_END));
282 i = sendNgPacket(nga, CODE_READ_REQ, attr);
284 /* the list will be filled again by recvNgPacket */
285 clearList(attr, (void(*)(void*))freeAttr);
288 i = recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr);
294 ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
299 /* check the switch error code */
300 ret = checkErrorCode(err, attr_error);
308 int writeRequest (struct ngadmin *nga, List *attr)
312 unsigned short attr_error;
319 } else if (nga->current == NULL) {
326 attr = createEmptyList();
328 /* add password attribute to start */
329 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
330 if (nga->encrypt_pass)
331 passwordEndecode(at->data, at->size);
332 pushFrontList(attr, at);
334 /* add end attribute to end */
335 pushBackList(attr, newEmptyAttr(ATTR_END));
337 i = sendNgPacket(nga, CODE_WRITE_REQ, attr);
339 /* the list will be filled again by recvNgPacket
340 but normally it will be still empty */
341 clearList(attr, (void(*)(void*))freeAttr);
344 i = recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr);
350 ret = ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
354 /* check the switch error code */
355 ret = checkErrorCode(err, attr_error);
359 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
360 destroyList(attr, (void(*)(void*))freeAttr);
367 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
370 const struct attr *at;
374 memset(sa, 0, sizeof(struct swi_attr));
376 for (ln = l->first; ln != NULL; ln = ln->next) {
382 len = min(at->size, PRODUCT_SIZE);
383 memcpy(sa->product, at->data, len);
384 trim(sa->product, len);
388 len = min(at->size, NAME_SIZE);
389 memcpy(sa->name, at->data, len);
394 memcpy(&sa->mac, at->data, ETH_ALEN);
398 sa->nc.ip = *(struct in_addr*)at->data;
402 sa->nc.netmask = *(struct in_addr*)at->data;
406 sa->nc.gw = *(struct in_addr*)at->data;
410 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
414 len = min(at->size, FIRMWARE_SIZE - 1);
415 memcpy(sa->firmware, at->data, len);
416 sa->firmware[len] = '\0';
419 case ATTR_PORTS_COUNT:
420 sa->ports = *(unsigned char*)at->data;