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 broadcast address */
35 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
37 perror("ioctl(SIOCGIFBRDADDR)");
41 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
43 /* get the interface MAC address */
44 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
46 perror("ioctl(SIOCGIFHWADDR)");
50 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
53 memset(&nga->local, 0, sizeof(struct sockaddr_in));
54 nga->local.sin_family = AF_INET;
55 nga->local.sin_port = htons(CLIENT_PORT);
57 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
64 /* allow broadcasting */
66 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
68 perror("setsockopt(SO_BROADCAST)");
72 /* prevent unicast packets from being routed by setting the TTL to 1 */
74 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
76 perror("setsockopt(IP_TTL)");
85 int stopNetwork (struct ngadmin *nga)
87 return close(nga->sock);
91 int forceInterface (struct ngadmin *nga)
97 As described bellow, when you have multiple interfaces, this forces the packet
98 to go to a particular interface.
100 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
102 perror("setsockopt(SO_BINDTODEVICE)");
107 If the switch's IP is not in your network range, for instance because you do
108 not have DHCP enabled or you started the switch after it, this allows to
109 bypass the routing tables and consider every address is directly reachable on
113 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
115 perror("setsockopt(SO_DONTROUTE)");
124 int updateTimeout (struct ngadmin *nga)
129 /* specify receive timeout */
130 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
132 perror("setsockopt(SO_RCVTIMEO)");
141 int sendNgPacket (struct ngadmin *nga, char code, const List *attr)
145 struct sockaddr_in remote;
146 const struct swi_attr *sa = nga->current;
151 np.maxlen = sizeof(buffer);
153 initNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
155 ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
159 memset(&remote, 0, sizeof(struct sockaddr_in));
160 remote.sin_family = AF_INET;
161 remote.sin_port = htons(SWITCH_PORT);
163 /* destination address selection */
164 if (sa != NULL && !nga->keepbroad)
165 remote.sin_addr = sa->nc.ip;
166 else if (nga->globalbroad)
167 remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
169 remote.sin_addr = nga->brd;
171 ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
180 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr)
184 struct sockaddr_in remote;
185 socklen_t slen = sizeof(struct sockaddr_in);
186 const struct swi_attr *sa = nga->current;
194 memset(&remote, 0, sizeof(struct sockaddr_in));
195 remote.sin_family = AF_INET;
202 FD_SET(nga->sock, &fs);
203 select(nga->sock+1, &fs, NULL, NULL, &rem); /* FIXME: non portable */
205 len = recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
213 if (ntohs(remote.sin_port) != SWITCH_PORT ||
214 len < (int)sizeof(struct ng_header) ||
215 !validateNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, nga->seq) ||
216 extractPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports) < 0)
220 *error = np.nh->error;
221 if (attr_error != NULL)
222 *attr_error = ntohs(np.nh->attr);
233 static int checkErrorCode (unsigned char err, unsigned short attr_error)
237 return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
238 case ERROR_INVALID_VALUE:
246 int readRequest (struct ngadmin *nga, List *attr)
250 unsigned short attr_error;
258 /* add end attribute to end */
259 pushBackList(attr, newEmptyAttr(ATTR_END));
261 i = sendNgPacket(nga, CODE_READ_REQ, attr);
263 /* the list will be filled again by recvNgPacket */
264 clearList(attr, (void(*)(void*))freeAttr);
267 i = recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr);
273 ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
278 /* check the switch error code */
279 ret = checkErrorCode(err, attr_error);
287 int writeRequest (struct ngadmin *nga, List *attr)
291 unsigned short attr_error;
298 } else if (nga->current == NULL) {
305 attr = createEmptyList();
307 /* add password attribute to start */
308 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
309 if (nga->encrypt_pass)
310 passwordEndecode(at->data, at->size);
311 pushFrontList(attr, at);
313 /* add end attribute to end */
314 pushBackList(attr, newEmptyAttr(ATTR_END));
316 i = sendNgPacket(nga, CODE_WRITE_REQ, attr);
318 /* the list will be filled again by recvNgPacket
319 but normally it will be still empty */
320 clearList(attr, (void(*)(void*))freeAttr);
323 i = recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr);
329 ret = ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
333 /* check the switch error code */
334 ret = checkErrorCode(err, attr_error);
338 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
339 destroyList(attr, (void(*)(void*))freeAttr);
346 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
349 const struct attr *at;
353 memset(sa, 0, sizeof(struct swi_attr));
355 for (ln = l->first; ln != NULL; ln = ln->next) {
361 len = min(at->size, PRODUCT_SIZE);
362 memcpy(sa->product, at->data, len);
363 trim(sa->product, len);
367 len = min(at->size, NAME_SIZE);
368 memcpy(sa->name, at->data, len);
373 memcpy(&sa->mac, at->data, ETH_ALEN);
377 sa->nc.ip = *(struct in_addr*)at->data;
381 sa->nc.netmask = *(struct in_addr*)at->data;
385 sa->nc.gw = *(struct in_addr*)at->data;
389 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
393 len = min(at->size, FIRMWARE_SIZE - 1);
394 memcpy(sa->firmware, at->data, len);
395 sa->firmware[len] = '\0';
398 case ATTR_PORTS_COUNT:
399 sa->ports = *(unsigned char*)at->data;