00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 #include <sys/confnet.h>
00045 #include <sys/confos.h>
00046 #include <sys/thread.h>
00047 #include <sys/timer.h>
00048 #include <sys/socket.h>
00049
00050 #include <netinet/in.h>
00051 #include <net/if_var.h>
00052
00053 #include <stdlib.h>
00054 #include <string.h>
00055
00056 #include <pro/discover.h>
00057
00062
00063 #ifndef NUT_THREAD_DISTSTACK
00064 #if defined(__AVR__)
00065 #define NUT_THREAD_DISTSTACK 384
00066 #else
00067 #define NUT_THREAD_DISTSTACK 512
00068 #endif
00069 #endif
00070
00071 #ifndef DISCOVERY_PORT
00072 #define DISCOVERY_PORT 9806
00073 #endif
00074
00075 typedef struct {
00076 uint32_t disopt_ipmask;
00077 uint16_t disopt_port;
00078 u_int disopt_flags;
00079 } DISCOVERY_OPTIONS;
00080
00081 static DISCOVERY_OPTIONS disopt;
00082 static uint32_t xid;
00083
00084 static int NutDiscoveryHandler(uint32_t ip, uint16_t port, DISCOVERY_TELE * dist, int len);
00085 static NutDiscoveryCallback discovery_callback = NutDiscoveryHandler;
00086
00094 int NutDiscoveryAnnTele(DISCOVERY_TELE * dist)
00095 {
00096 memset(dist, 0, sizeof(DISCOVERY_TELE));
00097 dist->dist_xid = xid;
00098 dist->dist_type = DIST_ANNOUNCE;
00099 dist->dist_ver = DISCOVERY_VERSION;
00100 memcpy(dist->dist_mac, confnet.cdn_mac, sizeof(dist->dist_mac));
00101 dist->dist_ip_addr = confnet.cdn_ip_addr;
00102 dist->dist_ip_mask = confnet.cdn_ip_mask;
00103 dist->dist_gateway = confnet.cdn_gateway;
00104 dist->dist_cip_addr = confnet.cdn_cip_addr;
00105 memcpy(dist->dist_hostname, confos.hostname, sizeof(dist->dist_hostname));
00106
00107 return sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom);
00108 }
00109
00117 int NutDiscoveryAppConf(DISCOVERY_TELE * dist)
00118 {
00119 memcpy(confos.hostname, dist->dist_hostname, sizeof(confos.hostname));
00120 NutSaveConfig();
00121
00122 memcpy(confnet.cdn_mac, dist->dist_mac, sizeof(confnet.cdn_mac));
00123 confnet.cdn_ip_addr = dist->dist_ip_addr;
00124 confnet.cdn_ip_mask = dist->dist_ip_mask;
00125 confnet.cdn_gateway = dist->dist_gateway;
00126 confnet.cdn_cip_addr = dist->dist_cip_addr;
00127
00128 return NutNetSaveConfig();
00129 }
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139 static int NutDiscoveryHandler(uint32_t ip, uint16_t port, DISCOVERY_TELE * dist, int len)
00140 {
00141 int rc = -1;
00142
00143
00144 if (len >= sizeof(DISCOVERY_TELE) - sizeof(dist->dist_custom)) {
00145 if (dist->dist_type == DIST_REQUEST) {
00146
00147 rc = NutDiscoveryAnnTele(dist);
00148 } else if (dist->dist_type == DIST_APPLY
00149 && dist->dist_xid == xid
00150 && dist->dist_ver >= DISCOVERY_VERSION) {
00151 xid += NutGetTickCount();
00152
00153 rc = NutDiscoveryAppConf(dist);
00154 }
00155 }
00156 return rc;
00157 }
00158
00159 THREAD(DiscoveryResponder, arg)
00160 {
00161 UDPSOCKET *sock;
00162 DISCOVERY_TELE *dist;
00163 uint32_t raddr;
00164 uint16_t rport;
00165 int len;
00166
00167
00168 while ((dist = malloc(sizeof(DISCOVERY_TELE))) == NULL) {
00169 NutSleep(1000);
00170 }
00171
00172
00173 while ((sock = NutUdpCreateSocket(disopt.disopt_port)) == NULL) {
00174 NutSleep(1000);
00175 }
00176
00177
00178 {
00179 uint16_t max_ms = sizeof(DISCOVERY_TELE) * 3;
00180
00181 NutUdpSetSockOpt(sock, SO_RCVBUF, &max_ms, sizeof(max_ms));
00182 }
00183
00184
00185 memcpy(&xid, &confnet.cdn_mac[2], sizeof(xid));
00186 xid += NutGetTickCount();
00187
00188
00189 if (disopt.disopt_flags & DISF_INITAL_ANN) {
00190
00191 NutSleep(500 + (xid & 0x7FF));
00192 if ((len = NutDiscoveryAnnTele(dist)) > 0) {
00193 NutUdpSendTo(sock, INADDR_BROADCAST, disopt.disopt_port, dist, len);
00194 }
00195 }
00196
00197
00198 for (;;) {
00199 len = NutUdpReceiveFrom(sock, &raddr, &rport, dist, sizeof(DISCOVERY_TELE), 0);
00200
00201 if ((raddr & disopt.disopt_ipmask) == raddr && len > 0 && discovery_callback) {
00202 if ((len = discovery_callback(raddr, rport, dist, len)) > 0) {
00203
00204 if ((raddr & confnet.cdn_ip_mask) != (confnet.cdn_ip_addr & confnet.cdn_ip_mask)) {
00205 raddr = INADDR_BROADCAST;
00206 }
00207 NutUdpSendTo(sock, raddr, disopt.disopt_port, dist, len);
00208 }
00209 }
00210
00211 NutSleep(100);
00212 }
00213 }
00214
00229 NutDiscoveryCallback NutRegisterDiscoveryCallback(NutDiscoveryCallback func)
00230 {
00231 NutDiscoveryCallback rc = discovery_callback;
00232
00233 discovery_callback = func;
00234
00235 return rc;
00236 }
00237
00255 int NutRegisterDiscovery(uint32_t ipmask, uint16_t port, u_int flags)
00256 {
00257 static HANDLE tid = NULL;
00258
00259 if (tid == NULL) {
00260 disopt.disopt_ipmask = ipmask;
00261 disopt.disopt_port = port ? port : DISCOVERY_PORT;
00262 disopt.disopt_flags = flags;
00263 tid = NutThreadCreate("udisc", DiscoveryResponder, NULL, NUT_THREAD_DISTSTACK);
00264 if (tid) {
00265 return 0;
00266 }
00267 }
00268 return -1;
00269 }
00270