9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
12 #include <nsdp/attr.h>
13 #include <nsdp/misc.h>
15 #include <nsdp/protocol.h>
20 int startNetwork (struct ngadmin *nga)
27 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
33 memset(&ifr, 0, sizeof(struct ifreq));
34 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
36 /* get the interface MAC address */
37 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
39 perror("ioctl(SIOCGIFHWADDR)");
43 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
46 memset(&nga->local, 0, sizeof(struct sockaddr_in));
47 nga->local.sin_family = AF_INET;
48 nga->local.sin_port = htons(CLIENT_PORT);
50 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
57 /* allow broadcasting */
59 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
61 perror("setsockopt(SO_BROADCAST)");
65 /* prevent unicast packets from being routed by setting the TTL to 1 */
67 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
69 perror("setsockopt(IP_TTL)");
78 int setBroadcastType (struct ngadmin *nga, bool value)
84 nga->globalbroad = value;
86 nga->brd.s_addr = (in_addr_t)0;
90 memset(&ifr, 0, sizeof(struct ifreq));
91 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
93 /* get the interface broadcast address */
94 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
96 perror("ioctl(SIOCGIFBRDADDR)");
97 nga->brd.s_addr = (in_addr_t)0;
98 nga->globalbroad = true;
102 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
108 int stopNetwork (struct ngadmin *nga)
110 return close(nga->sock);
114 int forceInterface (struct ngadmin *nga)
120 As described bellow, when you have multiple interfaces, this forces the packet
121 to go to a particular interface.
123 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
125 perror("setsockopt(SO_BINDTODEVICE)");
130 If the switch's IP is not in your network range, for instance because you do
131 not have DHCP enabled or you started the switch after it, this allows to
132 bypass the routing tables and consider every address is directly reachable on
136 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
138 perror("setsockopt(SO_DONTROUTE)");
147 int updateTimeout (struct ngadmin *nga)
152 /* specify receive timeout */
153 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
155 perror("setsockopt(SO_RCVTIMEO)");
164 static int checkErrorCode (const struct nsdp_cmd *nc)
169 return (nc->attr_error == ATTR_PASSWORD) ? ERR_BADPASS : ERR_DENIED;
171 case ERROR_INVALID_VALUE:
180 void prepareSend (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
182 struct swi_attr *sa = nga->current;
185 memset(nc, 0, sizeof(struct nsdp_cmd));
186 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
187 nc->remote_addr.sin_family = AF_INET;
188 nc->remote_addr.sin_port = htons(SWITCH_PORT);
190 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
191 nc->ports = sa->ports;
194 /* destination address selection */
195 if (sa != NULL && !nga->keepbroad)
196 nc->remote_addr.sin_addr = sa->nc.ip;
197 else if (nga->globalbroad)
198 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
200 nc->remote_addr.sin_addr = nga->brd;
202 nc->seqnum = ++nga->seq;
207 void prepareRecv (struct ngadmin *nga, struct nsdp_cmd *nc, unsigned char code)
209 struct swi_attr *sa = nga->current;
212 memset(nc, 0, sizeof(struct nsdp_cmd));
213 memcpy(&nc->client_mac, &nga->localmac, ETH_ALEN);
214 nc->remote_addr.sin_family = AF_INET;
215 nc->remote_addr.sin_port = htons(SWITCH_PORT);
217 memcpy(&nc->switch_mac, &sa->mac, ETH_ALEN);
218 nc->ports = sa->ports;
221 /* set filter on switch IP */
223 nc->remote_addr.sin_addr.s_addr = htonl(INADDR_ANY);
225 nc->remote_addr.sin_addr = sa->nc.ip;
227 nc->seqnum = nga->seq;
232 int readRequest (struct ngadmin *nga, List *attr)
243 /* add end attribute to end */
244 pushBackList(attr, newEmptyAttr(ATTR_END));
246 prepareSend(nga, &nc, CODE_READ_REQ);
247 i = sendNsdpPacket(nga->sock, &nc, attr);
249 /* do not destroy the list, it will be filled again later by recvNsdpPacket */
250 clearList(attr, (void(*)(void*))freeAttr);
253 prepareRecv(nga, &nc, CODE_READ_REP);
254 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
261 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
266 /* check the switch error code */
267 ret = checkErrorCode(&nc);
275 int writeRequest (struct ngadmin *nga, List *attr)
285 } else if (nga->current == NULL) {
292 attr = createEmptyList();
294 /* add password attribute to start */
295 at = newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password));
296 if (nga->encrypt_pass)
297 passwordEndecode(at->data, at->size);
298 pushFrontList(attr, at);
300 /* add end attribute to end */
301 pushBackList(attr, newEmptyAttr(ATTR_END));
303 prepareSend(nga, &nc, CODE_WRITE_REQ);
304 i = sendNsdpPacket(nga->sock, &nc, attr);
306 /* the list will be filled again by recvNgPacket
307 but normally it will be still empty */
308 clearList(attr, (void(*)(void*))freeAttr);
311 prepareRecv(nga, &nc, CODE_WRITE_REP);
312 i = recvNsdpPacket(nga->sock, &nc, attr, &nga->timeout);
319 ret = (errno == EAGAIN || errno == EWOULDBLOCK) ? ERR_TIMEOUT : ERR_NET;
323 /* check the switch error code */
324 ret = checkErrorCode(&nc);
328 /* the switch replies to write request by just a header (no attributes), so the list can be destroyed */
329 destroyList(attr, (void(*)(void*))freeAttr);
336 void extractSwitchAttributes (struct swi_attr *sa, const List *l)
339 const struct attr *at;
343 memset(sa, 0, sizeof(struct swi_attr));
345 for (ln = l->first; ln != NULL; ln = ln->next) {
351 len = min(at->size, PRODUCT_SIZE);
352 memcpy(sa->product, at->data, len);
353 trim(sa->product, len);
357 len = min(at->size, NAME_SIZE);
358 memcpy(sa->name, at->data, len);
363 memcpy(&sa->mac, at->data, ETH_ALEN);
367 sa->nc.ip = *(struct in_addr*)at->data;
371 sa->nc.netmask = *(struct in_addr*)at->data;
375 sa->nc.gw = *(struct in_addr*)at->data;
379 sa->nc.dhcp = (ntohs(*(unsigned short*)at->data) == 1);
383 len = min(at->size, FIRMWARE_SIZE - 1);
384 memcpy(sa->firmware, at->data, len);
385 sa->firmware[len] = '\0';
388 case ATTR_PORTS_COUNT:
389 sa->ports = *(unsigned char*)at->data;