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 ) {
26 // get the interface IP address
27 if ( (ret=ioctl(nga->sock, SIOCGIFADDR, &ifr))<0 ) {
28 perror("ioctl(SIOCGIFADDR)");
33 Here we have a problem: when you have multiple interfaces, sending a packet to
34 255.255.255.255 may not send it to the interface you want. If you bind() to
35 the address of the interface, you will not be able to receive broadcasts.
36 The only solution I have found yet is in this case to use
37 setsockopt(SO_BINDTODEVICE) but this requires root priviledges.
39 //local.sin_addr=(*(struct sockaddr_in*)&ifr.ifr_addr).sin_addr; // FIXME
41 // get the interface MAC address
42 if ( (ret=ioctl(nga->sock, SIOCGIFHWADDR, &ifr))<0 ) {
43 perror("ioctl(SIOCGIFHWADDR)");
47 memcpy(&nga->localmac, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
50 if ( (ret=bind(nga->sock, (struct sockaddr*)&nga->local, sizeof(struct sockaddr_in)))<0 ) {
58 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BROADCAST, &ret, sizeof(ret)))<0 ) {
59 perror("setsockopt(SO_BROADCAST)");
63 // prevent unicast packets from being routed
65 if ( (ret=setsockopt(nga->sock, IPPROTO_IP, IP_TTL, &ret, sizeof(ret)))<0 ) {
66 perror("setsockopt(IP_TTL)");
77 // ----------------------------------
78 int stopNetwork (struct ngadmin *nga) {
80 return close(nga->sock);
86 // -------------------------------------
87 int forceInterface (struct ngadmin *nga) {
93 As described bellow, when you have multiple interfaces, this forces the packet
94 to go to a particular interface.
96 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_BINDTODEVICE, nga->iface, strlen(nga->iface)+1))<0 ) {
97 perror("setsockopt(SO_BINDTODEVICE)");
102 If the switch's IP is not in your network range, for instance because you do
103 not have DHCP enabled or you started the switch after it, this allows to
104 bypass the routing tables and consider every address is directly reachable on
108 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_DONTROUTE, &ret, sizeof(ret)))<0 ) {
109 perror("setsockopt(SO_DONTROUTE)");
120 // ------------------------------------
121 int updateTimeout (struct ngadmin *nga) {
126 // specify receive timeout
127 if ( (ret=setsockopt(nga->sock, SOL_SOCKET, SO_RCVTIMEO, &nga->timeout, sizeof(struct timeval)))<0 ) {
128 perror("setsockopt(SO_RCVTIMEO)");
139 // ----------------------------------------------------------------
140 int sendNgPacket (struct ngadmin *nga, char code, const List *attr) {
146 struct sockaddr_in remote;
147 const struct swi_attr *sa=nga->current;
153 np.maxlen=sizeof(buffer);
155 initNgHeader(np.nh, code, &nga->localmac, sa==NULL ? &nullMac : &sa->mac , ++nga->seq);
158 for (ln=attr->first; ln!=NULL; ln=ln->next) {
160 addPacketAttr(&np, at->attr, at->size, at->data);
164 memset(&remote, 0, sizeof(struct sockaddr_in));
165 remote.sin_family=AF_INET;
166 remote.sin_addr.s_addr= sa==NULL || nga->keepbroad ? htonl(INADDR_BROADCAST) : sa->nc.ip.s_addr ;
167 remote.sin_port=htons(SWITCH_PORT);
169 if ( (ret=sendto(nga->sock, buffer, getPacketTotalSize(&np), 0, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)))<0 ) {
180 // -------------------------------------------------------------------------------------------------------------
181 int recvNgPacket (struct ngadmin *nga, char code, unsigned short *error, unsigned short *attr_error, List *attr) {
185 struct sockaddr_in remote;
186 socklen_t slen=sizeof(struct sockaddr_in);
187 const struct swi_attr *sa=nga->current;
192 np.maxlen=sizeof(buffer);
194 memset(&remote, 0, sizeof(struct sockaddr_in));
195 remote.sin_family=AF_INET;
199 len=recvfrom(nga->sock, buffer, sizeof(buffer), 0, (struct sockaddr*)&remote, &slen);
205 if ( ntohs(remote.sin_port)==SWITCH_PORT && len>=(int)sizeof(struct ng_header) && validateNgHeader(np.nh, code, &nga->localmac, sa==NULL ? NULL : &sa->mac , nga->seq) ) {
207 extractPacketAttributes(&np, error, attr_error, attr);
221 // ----------------------------------------------
222 int readRequest (struct ngadmin *nga, List *attr) {
225 unsigned short err, attr_error;
233 // add end attribute to end
234 pushBackList(attr, newEmptyAttr(ATTR_END));
236 i=sendNgPacket(nga, CODE_READ_REQ, attr);
238 // the list will be filled again by recvNgPacket
239 clearList(attr, (void(*)(void*))freeAttr);
241 if ( i<0 || (i=recvNgPacket(nga, CODE_READ_REP, &err, &attr_error, attr))<0 ) {
242 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
246 if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
261 // -----------------------------------------------
262 int writeRequest (struct ngadmin *nga, List *attr) {
265 unsigned short err, attr_error;
271 } else if ( nga->current==NULL ) {
278 attr=createEmptyList();
281 // add password attribute to start
282 pushFrontList(attr, newAttr(ATTR_PASSWORD, strlen(nga->password), strdup(nga->password)));
284 // add end attribute to end
285 pushBackList(attr, newEmptyAttr(ATTR_END));
287 i=sendNgPacket(nga, CODE_WRITE_REQ, attr);
289 // the list will be filled again by recvNgPacket
290 // but normally it will be still empty
291 clearList(attr, (void(*)(void*))freeAttr);
293 if ( i<0 || (i=recvNgPacket(nga, CODE_WRITE_REP, &err, &attr_error, attr))<0 ) {
294 ret= ( errno==EAGAIN || errno==EWOULDBLOCK ) ? ERR_TIMEOUT : ERR_NET ;
298 if ( err==0x0700 && attr_error==ATTR_PASSWORD ) {
307 // the switch replies to write request by just a header (no attributes), so the list can be destroyed
308 destroyList(attr, (void(*)(void*))freeAttr);