7 // -----------------------------------
8 int startNetwork (struct ngadmin *nga) {
14 memset(&nga->local, 0, sizeof(struct sockaddr_in));
15 nga->local.sin_family=AF_INET;
16 nga->local.sin_port=htons(CLIENT_PORT);
18 memset(&ifr, 0, sizeof(struct ifreq));
19 strncpy(ifr.ifr_name, nga->iface, IFNAMSIZ-1);
21 if ( (nga->sock=socket(AF_INET, SOCK_DGRAM, 0))<0 ) {
27 // get the interface IP address
28 if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
29 perror("ioctl(SIOCGIFADDR)");
35 Here we have a problem: when you have multiple interfaces, sending a packet to
36 255.255.255.255 may not send it to the interface you want. If you bind() to
37 the address of the interface, you will not be able to receive broadcasts.
38 The only solution I have found yet is in this case to use
39 setsockopt(SO_BINDTODEVICE) but this requires root priviledges.
41 //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
43 // get the interface broadcast address
44 if ( (ret=ioctl(nga->sock, SIOCGIFBRDADDR, &ifr))<0 ) {
45 perror("ioctl(SIOCGIFBRDADDR)");
49 nga->brd=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr;
51 // get the interface MAC address
52 if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
53 perror("ioctl(SIOCGIFHWADDR)");
57 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
60 if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
68 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
69 perror("setsockopt(SO_BROADCAST)");
73 // prevent unicast packets from being routed
75 if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
76 perror("setsockopt(IP_TTL)");
87 // ----------------------------------
88 int stopNetwork (struct ngadmin *nga) {
90 return close(nga->sock);
96 // -------------------------------------
97 int forceInterface (struct ngadmin *nga) {
103 As described bellow, when you have multiple interfaces, this forces the packet
104 to go to a particular interface.
106 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
107 perror("setsockopt(SO_BINDTODEVICE)");
112 If the switch's IP is not in your network range, for instance because you do
113 not have DHCP enabled or you started the switch after it, this allows to
114 bypass the routing tables and consider every address is directly reachable on
118 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
119 perror("setsockopt(SO_DONTROUTE)");
130 // ------------------------------------
131 int updateTimeout (struct ngadmin *nga) {
136 // specify receive timeout
137 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
138 perror("setsockopt(SO_RCVTIMEO)");
149 // ----------------------------------------------------------------
150 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
156 struct sockaddr_in remote;
157 const struct swi_attr *sa=nga->current;
164 np.maxlen=sizeof(buffer);
166 initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , ++nga->seq);
169 for (ln=attr->first; ln!=NULL; ln=ln->next) {
171 addPacketAttr(&np, at->attr, at->size, at->data);
175 memset(&remote, 0, sizeof(struct sockaddr_in));
176 remote.sin_family=AF_INET;
177 remote.sin_port=htons(SWITCH_PORT);
179 if ( sa!=NULL && !nga->keepbroad ) remote.sin_addr=sa->nc.ip;
180 else if ( nga->globalbroad ) remote.sin_addr.s_addr=htonl(INADDR_BROADCAST);
181 else remote.sin_addr=nga->brd;
184 if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
195 static int my_poll (struct pollfd *fds, nfds_t nfds, struct timeval *timeout) {
198 struct timeval start, stop;
201 if ( timeout!=NULL ) {
202 if ( timeout->tv_sec<0 || timeout->tv_usec<0 ) rem=0;
203 else rem=timeout->tv_sec*1000+timeout->tv_usec/1000;
206 gettimeofday(&start, NULL);
207 ret=poll(fds, nfds, rem);
208 gettimeofday(&stop, NULL);
210 if ( timeout!=NULL ) {
211 rem-=(stop.tv_sec-start.tv_sec)*1000+(stop.tv_usec-start.tv_usec)/1000;
212 if ( ret<=0 || rem<0 ) rem=0;
213 printf("tv_sec = %i, tv_usec = %i\n", start.tv_sec, start.tv_usec);
214 printf("tv_sec = %i, tv_usec = %i\n", stop.tv_sec, stop.tv_usec);
215 printf("rem = %i\n", rem);
216 timeout->tv_sec=rem/1000;
217 timeout->tv_usec=(rem%1000)*1000;
227 // ------------------------------------------------------------------------------------------------------------
228 int recvNgPacket (struct ngadmin *nga, char code, unsigned char *error, unsigned short *attr_error, List *attr) {
232 struct sockaddr_in remote;
233 socklen_t slen=sizeof(struct sockaddr_in);
234 const struct swi_attr *sa=nga->current;
243 memset(&remote, 0, sizeof(struct sockaddr_in));
244 remote.sin_family=AF_INET;
253 //my_poll(&fds, 1, &rem);
255 FD_SET(nga->sock, &fs);
256 select(nga->sock+1, &fs, NULL, NULL, &rem);
258 len=recvfrom(nga->sock, buffer, sizeof(buffer), MSG_DONTWAIT, (struct sockaddr*)&remote, &slen);
266 ntohs(remote.sin_port)!=SWITCH_PORT ||
267 len<(int)sizeof(struct ng_header) ||
268 !validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) ||
269 extractPacketAttributes(&np, error, attr_error, attr)<0
284 static int checkErrorCode (unsigned char err, unsigned short attr_error) {
287 if ( err==ERROR_INVALID_PASSWORD && attr_error==ATTR_PASSWORD ) {
291 if ( err==ERROR_INVALID_VALUE ) {
302 // ----------------------------------------------
303 int readRequest (struct ngadmin *nga, List *attr) {
307 unsigned short attr_error;
315 // add end attribute to end
316 pushBackList(attr, newEmptyAttr(ATTR_END));
318 i=sendNgPacket(nga, CODE_READ_REQ, attr);
320 // the list will be filled again by recvNgPacket
321 clearList(attr, (void(*)(void*))freeAttr);
323 if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
324 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
330 ret=checkErrorCode(err, attr_error);
341 // -----------------------------------------------
342 int writeRequest (struct ngadmin *nga, List *attr) {
346 unsigned short attr_error;
352 } else if ( nga->current==NULL ) {
359 attr=createEmptyList();
362 // add password attribute to start
363 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
365 // add end attribute to end
366 pushBackList(attr, newEmptyAttr(ATTR_END));
368 i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
370 // the list will be filled again by recvNgPacket
371 // but normally it will be still empty
372 clearList(attr, (void(*)(void*))freeAttr);
374 if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
375 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
380 ret=checkErrorCode(err, attr_error);
384 // the switch replies to write request by just a header (no attributes), so the list can be destroyed
385 destroyList(attr, (void(*)(void*))freeAttr);