9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
19 int startNetwork (struct ngadmin *nga)
26 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
32 memset(&ifr, 0, sizeof(struct ifreq));
33 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
35 /* get the interface MAC address */
36 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
38 perror("ioctl(SIOCGIFHWADDR)");
42 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
45 memset(&nga->local, 0, sizeof(struct sockaddr_in));
46 nga->local.sin_family = AF_INET;
47 nga->local.sin_port = htons(CLIENT_PORT);
49 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
56 /* allow broadcasting */
58 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
60 perror("setsockopt(SO_BROADCAST)");
64 /* prevent unicast packets from being routed by setting the TTL to 1 */
66 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
68 perror("setsockopt(IP_TTL)");
77 int setBroadcastType (struct ngadmin *nga, bool value)
83 nga->globalbroad = value;
85 nga->brd.s_addr = (in_addr_t)0;
89 memset(&ifr, 0, sizeof(struct ifreq));
90 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
92 /* get the interface broadcast address */
93 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
95 perror("ioctl(SIOCGIFBRDADDR)");
96 nga->brd.s_addr = (in_addr_t)0;
97 nga->globalbroad = true;
101 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
107 int stopNetwork (struct ngadmin *nga)
109 return close(nga->sock);
113 int forceInterface (struct ngadmin *nga)
119 As described bellow, when you have multiple interfaces, this forces the packet
120 to go to a particular interface.
122 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
124 perror("setsockopt(SO_BINDTODEVICE)");
129 If the switch's IP is not in your network range, for instance because you do
130 not have DHCP enabled or you started the switch after it, this allows to
131 bypass the routing tables and consider every address is directly reachable on
135 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
137 perror("setsockopt(SO_DONTROUTE)");
146 int updateTimeout (struct ngadmin *nga)
151 /* specify receive timeout */
152 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
154 perror("setsockopt(SO_RCVTIMEO)");
163 int sendNsdpPacket (struct ngadmin *nga, char code, const List *attr)
165 unsigned char buffer[1500];
166 struct nsdp_packet np;
167 struct sockaddr_in remote;
168 const struct swi_attr *sa = nga->current;
173 np.maxlen = sizeof(buffer);
175 initNsdpHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
177 ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
181 memset(&remote, 0, sizeof(struct sockaddr_in));
182 remote.sin_family = AF_INET;
183 remote.sin_port = htons(SWITCH_PORT);
185 /* destination address selection */
186 if (sa != NULL && !nga->keepbroad)
187 remote.sin_addr = sa->nc.ip;
188 else if (nga->globalbroad)
189 remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
191 remote.sin_addr = nga->brd;
193 ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
202 int recvNsdpPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr)
204 unsigned char buffer[1500];
205 struct nsdp_packet np;
206 struct sockaddr_in remote;
207 socklen_t slen = sizeof(struct sockaddr_in);
208 const struct swi_attr *sa = nga->current;
216 memset(&remote, 0, sizeof(struct sockaddr_in));
217 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);
233 if (ntohs(remote.sin_port) != SWITCH_PORT ||
234 len < (int)sizeof(struct nsdp_header) ||
235 !validateNsdpHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, nga->seq) ||
236 extractPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports) < 0)
240 *error = np.nh->error;
241 if (attr_error != NULL)
242 *attr_error = ntohs(np.nh->attr);
253 static int checkErrorCode (unsigned char err, unsigned short attr_error)
257 return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
258 case ERROR_INVALID_VALUE:
266 int readRequest (struct ngadmin *nga, List *attr)
270 unsigned short attr_error;
278 /* add end attribute to end */
279 pushBackList(attr, newEmptyAttr(ATTR_END));
281 i = sendNsdpPacket(nga, CODE_READ_REQ, attr);
283 /* the list will be filled again by recvNgPacket */
284 clearList(attr, (void(*)(void*))freeAttr);
287 i = recvNsdpPacket(nga, CODE_READ_REP, &err, &attr_error, attr);
293 ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
298 /* check the switch error code */
299 ret = checkErrorCode(err, attr_error);
307 int writeRequest (struct ngadmin *nga, List *attr)
311 unsigned short attr_error;
318 } else if (nga->current == NULL) {
325 attr = createEmptyList();
327 /* add password attribute to start */
328 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
329 if (nga->encrypt_pass)
330 passwordEndecode(at->data, at->size);
331 pushFrontList(attr, at);
333 /* add end attribute to end */
334 pushBackList(attr, newEmptyAttr(ATTR_END));
336 i = sendNsdpPacket(nga, CODE_WRITE_REQ, attr);
338 /* the list will be filled again by recvNgPacket
339 but normally it will be still empty */
340 clearList(attr, (void(*)(void*))freeAttr);
343 i = recvNsdpPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr);
349 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET ;
353 /* check the switch error code */
354 ret = checkErrorCode(err, attr_error);
358 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
359 destroyList(attr, (void(*)(void*))freeAttr);
366 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
369 const struct attr *at;
373 memset(sa, 0, sizeof(struct swi_attr));
375 for (ln = l->first; ln != NULL; ln = ln->next) {
381 len = min(at->size, PRODUCT_SIZE);
382 memcpy(sa->product, at->data, len);
383 trim(sa->product, len);
387 len = min(at->size, NAME_SIZE);
388 memcpy(sa->name, at->data, len);
393 memcpy(&sa->mac, at->data, ETH_ALEN);
397 sa->nc.ip = *(struct in_addr*)at->data;
401 sa->nc.netmask = *(struct in_addr*)at->data;
405 sa->nc.gw = *(struct in_addr*)at->data;
409 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
413 len = min(at->size, FIRMWARE_SIZE - 1);
414 memcpy(sa->firmware, at->data, len);
415 sa->firmware[len] = '\0';
418 case ATTR_PORTS_COUNT:
419 sa->ports = *(unsigned char*)at->data;