9 #include <netinet/ether.h>
10 #include <sys/ioctl.h>
17 int startNetwork (struct ngadmin *nga)
24 nga->sock = socket(AF_INET, SOCK_DGRAM, 0);
30 memset(&ifr, 0, sizeof(struct ifreq));
31 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ - 1);
33 /* get the interface broadcast address */
34 ret = ioctl(nga->sock, SIOCGIFBRDADDR, &ifr);
36 perror("ioctl(SIOCGIFBRDADDR)");
40 nga->brd = (*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
42 /* get the interface MAC address */
43 ret = ioctl(nga->sock, SIOCGIFHWADDR, &ifr);
45 perror("ioctl(SIOCGIFHWADDR)");
49 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
52 memset(&nga->local, 0, sizeof(struct sockaddr_in));
53 nga->local.sin_family = AF_INET;
54 nga->local.sin_port = htons(CLIENT_PORT);
56 ret = bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in));
63 /* allow broadcasting */
65 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret));
67 perror("setsockopt(SO_BROADCAST)");
71 /* prevent unicast packets from being routed by setting the TTL to 1 */
73 ret = setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret));
75 perror("setsockopt(IP_TTL)");
84 int stopNetwork (struct ngadmin *nga)
86 return close(nga->sock);
90 int forceInterface (struct ngadmin *nga)
96 As described bellow, when you have multiple interfaces, this forces the packet
97 to go to a particular interface.
99 ret = setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface) + 1);
101 perror("setsockopt(SO_BINDTODEVICE)");
106 If the switch's IP is not in your network range, for instance because you do
107 not have DHCP enabled or you started the switch after it, this allows to
108 bypass the routing tables and consider every address is directly reachable on
112 ret = setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret));
114 perror("setsockopt(SO_DONTROUTE)");
123 int updateTimeout (struct ngadmin *nga)
128 /* specify receive timeout */
129 ret = setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval));
131 perror("setsockopt(SO_RCVTIMEO)");
140 int sendNgPacket (struct ngadmin *nga, char code, const List *attr)
144 struct sockaddr_in remote;
145 const struct swi_attr *sa = nga->current;
150 np.maxlen = sizeof(buffer);
152 initNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, ++nga->seq);
154 ret = addPacketAttributes(&np, attr, sa == NULL ? 0 : sa->ports);
158 memset(&remote, 0, sizeof(struct sockaddr_in));
159 remote.sin_family = AF_INET;
160 remote.sin_port = htons(SWITCH_PORT);
162 /* destination address selection */
163 if (sa != NULL && !nga->keepbroad)
164 remote.sin_addr = sa->nc.ip;
165 else if (nga->globalbroad)
166 remote.sin_addr.s_addr = htonl(INADDR_BROADCAST);
168 remote.sin_addr = nga->brd;
170 ret = sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in));
179 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr, unsigned short filter_attr)
183 struct sockaddr_in remote;
184 socklen_t slen = sizeof(struct sockaddr_in);
185 const struct swi_attr *sa = nga->current;
193 memset(&remote, 0, sizeof(struct sockaddr_in));
194 remote.sin_family = AF_INET;
201 FD_SET(nga->sock, &fs);
202 select(nga->sock+1, &fs, NULL, NULL, &rem); /* FIXME: non portable */
204 len = recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
212 if (ntohs(remote.sin_port) != SWITCH_PORT ||
213 len < (int)sizeof(struct ng_header) ||
214 !validateNgHeader(np.nh, code, &nga->localmac, sa == NULL ? NULL : &sa->mac, nga->seq) ||
215 extractPacketAttributes(&np, error, attr_error, attr, filter_attr, sa == NULL ? 0 : sa->ports) < 0)
227 static int checkErrorCode (unsigned char err, unsigned short attr_error)
231 return attr_error == ATTR_PASSWORD ? ERR_BADPASS : ERR_DENIED;
232 case ERROR_INVALID_VALUE:
240 int readRequest (struct ngadmin *nga, List *attr, unsigned short filter_attr)
244 unsigned short attr_error;
252 /* add end attribute to end */
253 pushBackList(attr, newEmptyAttr(ATTR_END));
255 i = sendNgPacket(nga, CODE_READ_REQ, attr);
257 /* the list will be filled again by recvNgPacket */
258 clearList(attr, (void(*)(void*))freeAttr);
261 i = recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr, filter_attr);
267 ret = ( errno == EAGAIN || errno == EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET;
272 /* check the switch error code */
273 ret = checkErrorCode(err, attr_error);
281 int writeRequest (struct ngadmin *nga, List *attr)
285 unsigned short attr_error;
291 } else if (nga->current == NULL) {
298 attr = createEmptyList();
300 /* add password attribute to start */
301 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
303 /* add end attribute to end */
304 pushBackList(attr, newEmptyAttr(ATTR_END));
306 i = sendNgPacket(nga, CODE_WRITE_REQ, attr);
308 /* the list will be filled again by recvNgPacket
309 but normally it will be still empty */
310 clearList(attr, (void(*)(void*))freeAttr);
313 i = recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr, ATTR_END);
319 ret = ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
323 /* check the switch error code */
324 ret = checkErrorCode(err, attr_error);
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;