802.11 association handling functions


Functions

static void net80211_step_associate (struct process *proc)
 Step 802.11 association process.
static void net80211_handle_auth (struct net80211_device *dev, struct io_buffer *iob)
 Handle receipt of 802.11 authentication frame.
static void net80211_handle_assoc_reply (struct net80211_device *dev, struct io_buffer *iob)
 Handle receipt of 802.11 association reply frame.
static int net80211_send_disassoc (struct net80211_device *dev, int reason, int deauth)
 Send 802.11 disassociation frame.
static void net80211_handle_mgmt (struct net80211_device *dev, struct io_buffer *iob, int signal)
 Handle receipt of 802.11 management frame.

Function Documentation

static void net80211_step_associate ( struct process proc  )  [static]

Step 802.11 association process.

Parameters:
proc Association process

Definition at line 1657 of file net80211.c.

References net80211_device::assoc, net80211_device::assoc_rc, ASSOC_RETRIES, ASSOC_TIMEOUT, net80211_device::associating, net80211_hw_info::bands, net80211_device::bssid, net80211_wlan::bssid, container_of, net80211_device::ctx, currticks(), DBGC, ENOMEM, net80211_wlan::essid, net80211_device::essid, eth_ntoa(), ETIMEDOUT, fetch_intz_setting(), free(), net80211_device::handshaker, net80211_device::hw, IEEE80211_AUTH_OPEN_SYSTEM, IEEE80211_AUTH_SHARED_KEY, IEEE80211_STATUS_AUTH_ALGO_UNSUPP, IEEE80211_STATUS_AUTH_CHALL_INVALID, IEEE80211_STATUS_SUCCESS, net80211_assoc_ctx::last_packet, net80211_assoc_ctx::method, NET80211_ASSOCIATED, NET80211_AUTHENTICATED, NET80211_AUTO_SSID, net80211_autoassociate(), NET80211_BAND_BIT_5GHZ, NET80211_CRYPTO_SYNCED, net80211_free_wlan(), net80211_prepare_assoc(), net80211_prepare_probe(), net80211_probe_finish_best(), net80211_probe_start(), net80211_probe_step(), NET80211_PROBED, net80211_send_assoc(), net80211_send_auth(), NET80211_STATUS_MASK, NET80211_WAITING, NET80211_WORKING, net80211_device::netdev, netdev_link_err(), netdev_link_up(), NULL, net80211_device::probe, net80211_device::proc_assoc, process_del(), rc80211_init(), net80211_device::rctl, net80211_handshaker::start, net80211_handshaker::started, net80211_device::state, net80211_handshaker::step, strerror(), net80211_assoc_ctx::times_tried, and zalloc().

Referenced by net80211_alloc().

01658 {
01659         struct net80211_device *dev =
01660             container_of ( proc, struct net80211_device, proc_assoc );
01661         int rc = 0;
01662         int status = dev->state & NET80211_STATUS_MASK;
01663 
01664         /*
01665          * We use a sort of state machine implemented using bits in
01666          * the dev->state variable. At each call, we take the
01667          * logically first step that has not yet succeeded; either it
01668          * has not been tried yet, it's being retried, or it failed.
01669          * If it failed, we return an error indication; otherwise we
01670          * perform the step. If it succeeds, RX handling code will set
01671          * the appropriate status bit for us.
01672          *
01673          * Probe works a bit differently, since we have to step it
01674          * on every call instead of waiting for a packet to arrive
01675          * that will set the completion bit for us.
01676          */
01677 
01678         /* If we're waiting for a reply, check for timeout condition */
01679         if ( dev->state & NET80211_WAITING ) {
01680                 /* Sanity check */
01681                 if ( ! dev->associating )
01682                         return;
01683 
01684                 if ( currticks() - dev->ctx.assoc->last_packet > ASSOC_TIMEOUT ) {
01685                         /* Timed out - fail if too many retries, or retry */
01686                         dev->ctx.assoc->times_tried++;
01687                         if ( ++dev->ctx.assoc->times_tried > ASSOC_RETRIES ) {
01688                                 rc = -ETIMEDOUT;
01689                                 goto fail;
01690                         }
01691                 } else {
01692                         /* Didn't time out - let it keep going */
01693                         return;
01694                 }
01695         } else {
01696                 if ( dev->state & NET80211_PROBED )
01697                         dev->ctx.assoc->times_tried = 0;
01698         }
01699 
01700         if ( ! ( dev->state & NET80211_PROBED ) ) {
01701                 /* state: probe */
01702 
01703                 if ( ! dev->ctx.probe ) {
01704                         /* start probe */
01705                         int active = fetch_intz_setting ( NULL,
01706                                                 &net80211_active_setting );
01707                         int band = dev->hw->bands;
01708 
01709                         if ( active )
01710                                 band &= ~NET80211_BAND_BIT_5GHZ;
01711 
01712                         rc = net80211_prepare_probe ( dev, band, active );
01713                         if ( rc )
01714                                 goto fail;
01715 
01716                         dev->ctx.probe = net80211_probe_start ( dev, dev->essid,
01717                                                                 active );
01718                         if ( ! dev->ctx.probe ) {
01719                                 dev->assoc_rc = -ENOMEM;
01720                                 goto fail;
01721                         }
01722                 }
01723 
01724                 rc = net80211_probe_step ( dev->ctx.probe );
01725                 if ( ! rc ) {
01726                         return; /* still going */
01727                 }
01728 
01729                 dev->associating = net80211_probe_finish_best ( dev->ctx.probe );
01730                 dev->ctx.probe = NULL;
01731                 if ( ! dev->associating ) {
01732                         if ( rc > 0 ) /* "successful" probe found nothing */
01733                                 rc = -ETIMEDOUT;
01734                         goto fail;
01735                 }
01736 
01737                 /* If we probed using a broadcast SSID, record that
01738                    fact for the settings applicator before we clobber
01739                    it with the specific SSID we've chosen. */
01740                 if ( ! dev->essid[0] )
01741                         dev->state |= NET80211_AUTO_SSID;
01742 
01743                 DBGC ( dev, "802.11 %p found network %s (%s)\n", dev,
01744                        dev->associating->essid,
01745                        eth_ntoa ( dev->associating->bssid ) );
01746 
01747                 dev->ctx.assoc = zalloc ( sizeof ( *dev->ctx.assoc ) );
01748                 if ( ! dev->ctx.assoc ) {
01749                         rc = -ENOMEM;
01750                         goto fail;
01751                 }
01752 
01753                 dev->state |= NET80211_PROBED;
01754                 dev->ctx.assoc->method = IEEE80211_AUTH_OPEN_SYSTEM;
01755 
01756                 return;
01757         }
01758 
01759         /* Record time of sending the packet we're about to send, for timeout */
01760         dev->ctx.assoc->last_packet = currticks();
01761 
01762         if ( ! ( dev->state & NET80211_AUTHENTICATED ) ) {
01763                 /* state: prepare and authenticate */
01764 
01765                 if ( status != IEEE80211_STATUS_SUCCESS ) {
01766                         /* we tried authenticating already, but failed */
01767                         int method = dev->ctx.assoc->method;
01768 
01769                         if ( method == IEEE80211_AUTH_OPEN_SYSTEM &&
01770                              ( status == IEEE80211_STATUS_AUTH_CHALL_INVALID ||
01771                                status == IEEE80211_STATUS_AUTH_ALGO_UNSUPP ) ) {
01772                                 /* Maybe this network uses Shared Key? */
01773                                 dev->ctx.assoc->method =
01774                                         IEEE80211_AUTH_SHARED_KEY;
01775                         } else {
01776                                 goto fail;
01777                         }
01778                 }
01779 
01780                 DBGC ( dev, "802.11 %p authenticating with method %d\n", dev,
01781                        dev->ctx.assoc->method );
01782 
01783                 rc = net80211_prepare_assoc ( dev, dev->associating );
01784                 if ( rc )
01785                         goto fail;
01786 
01787                 rc = net80211_send_auth ( dev, dev->associating,
01788                                           dev->ctx.assoc->method );
01789                 if ( rc )
01790                         goto fail;
01791 
01792                 return;
01793         }
01794 
01795         if ( ! ( dev->state & NET80211_ASSOCIATED ) ) {
01796                 /* state: associate */
01797 
01798                 if ( status != IEEE80211_STATUS_SUCCESS )
01799                         goto fail;
01800 
01801                 DBGC ( dev, "802.11 %p associating\n", dev );
01802 
01803                 if ( dev->handshaker && dev->handshaker->start &&
01804                      ! dev->handshaker->started ) {
01805                         rc = dev->handshaker->start ( dev );
01806                         if ( rc < 0 )
01807                                 goto fail;
01808                         dev->handshaker->started = 1;
01809                 }
01810 
01811                 rc = net80211_send_assoc ( dev, dev->associating );
01812                 if ( rc )
01813                         goto fail;
01814 
01815                 return;
01816         }
01817 
01818         if ( ! ( dev->state & NET80211_CRYPTO_SYNCED ) ) {
01819                 /* state: crypto sync */
01820                 DBGC ( dev, "802.11 %p security handshaking\n", dev );
01821 
01822                 if ( ! dev->handshaker || ! dev->handshaker->step ) {
01823                         dev->state |= NET80211_CRYPTO_SYNCED;
01824                         return;
01825                 }
01826 
01827                 rc = dev->handshaker->step ( dev );
01828 
01829                 if ( rc < 0 ) {
01830                         /* Only record the returned error if we're
01831                            still marked as associated, because an
01832                            asynchronous error will have already been
01833                            reported to net80211_deauthenticate() and
01834                            assoc_rc thereby set. */
01835                         if ( dev->state & NET80211_ASSOCIATED )
01836                                 dev->assoc_rc = rc;
01837                         rc = 0;
01838                         goto fail;
01839                 }
01840 
01841                 if ( rc > 0 ) {
01842                         dev->assoc_rc = 0;
01843                         dev->state |= NET80211_CRYPTO_SYNCED;
01844                 }
01845                 return;
01846         }
01847 
01848         /* state: done! */
01849         netdev_link_up ( dev->netdev );
01850         dev->assoc_rc = 0;
01851         dev->state &= ~NET80211_WORKING;
01852 
01853         free ( dev->ctx.assoc );
01854         dev->ctx.assoc = NULL;
01855 
01856         net80211_free_wlan ( dev->associating );
01857         dev->associating = NULL;
01858 
01859         dev->rctl = rc80211_init ( dev );
01860 
01861         process_del ( proc );
01862 
01863         DBGC ( dev, "802.11 %p associated with %s (%s)\n", dev,
01864                dev->essid, eth_ntoa ( dev->bssid ) );
01865 
01866         return;
01867 
01868  fail:
01869         dev->state &= ~( NET80211_WORKING | NET80211_WAITING );
01870         if ( rc )
01871                 dev->assoc_rc = rc;
01872 
01873         netdev_link_err ( dev->netdev, dev->assoc_rc );
01874 
01875         /* We never reach here from the middle of a probe, so we don't
01876            need to worry about freeing dev->ctx.probe. */
01877 
01878         if ( dev->state & NET80211_PROBED ) {
01879                 free ( dev->ctx.assoc );
01880                 dev->ctx.assoc = NULL;
01881         }
01882 
01883         net80211_free_wlan ( dev->associating );
01884         dev->associating = NULL;
01885 
01886         process_del ( proc );
01887 
01888         DBGC ( dev, "802.11 %p association failed (state=%04x): "
01889                "%s\n", dev, dev->state, strerror ( dev->assoc_rc ) );
01890 
01891         /* Try it again: */
01892         net80211_autoassociate ( dev );
01893 }

static void net80211_handle_auth ( struct net80211_device dev,
struct io_buffer iob 
) [static]

Handle receipt of 802.11 authentication frame.

Parameters:
dev 802.11 device
iob I/O buffer
If the authentication method being used is Shared Key, and the frame that was received included challenge text, the frame is encrypted using the cryptosystem currently in effect and sent back to the AP to complete the authentication.

Definition at line 2240 of file net80211.c.

References ieee80211_frame::addr1, ieee80211_frame::addr2, ieee80211_frame::addr3, ieee80211_auth::algorithm, net80211_device::crypto, ieee80211_frame::data, io_buffer::data, DBGC, net80211_crypto::encrypt, ETH_ALEN, IEEE80211_AUTH_SHARED_KEY, IEEE80211_STATUS_FAILURE, IEEE80211_STATUS_SUCCESS, memcpy, NET80211_AUTHENTICATED, net80211_set_state(), NET80211_WAITING, net80211_device::netdev, netdev_tx(), ieee80211_auth::status, and ieee80211_auth::tx_seq.

Referenced by net80211_handle_mgmt().

02242 {
02243         struct ieee80211_frame *hdr = iob->data;
02244         struct ieee80211_auth *auth =
02245             ( struct ieee80211_auth * ) hdr->data;
02246 
02247         if ( auth->tx_seq & 1 ) {
02248                 DBGC ( dev, "802.11 %p authentication received improperly "
02249                        "directed frame (seq. %d)\n", dev, auth->tx_seq );
02250                 net80211_set_state ( dev, NET80211_WAITING, 0,
02251                                      IEEE80211_STATUS_FAILURE );
02252                 return;
02253         }
02254 
02255         if ( auth->status != IEEE80211_STATUS_SUCCESS ) {
02256                 DBGC ( dev, "802.11 %p authentication failed: status %d\n",
02257                        dev, auth->status );
02258                 net80211_set_state ( dev, NET80211_WAITING, 0,
02259                                      auth->status );
02260                 return;
02261         }
02262 
02263         if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY && ! dev->crypto ) {
02264                 DBGC ( dev, "802.11 %p can't perform shared-key authentication "
02265                        "without a cryptosystem\n", dev );
02266                 net80211_set_state ( dev, NET80211_WAITING, 0,
02267                                      IEEE80211_STATUS_FAILURE );
02268                 return;
02269         }
02270 
02271         if ( auth->algorithm == IEEE80211_AUTH_SHARED_KEY &&
02272              auth->tx_seq == 2 ) {
02273                 /* Since the iob we got is going to be freed as soon
02274                    as we return, we can do some in-place
02275                    modification. */
02276                 auth->tx_seq = 3;
02277                 auth->status = 0;
02278 
02279                 memcpy ( hdr->addr2, hdr->addr1, ETH_ALEN );
02280                 memcpy ( hdr->addr1, hdr->addr3, ETH_ALEN );
02281 
02282                 netdev_tx ( dev->netdev,
02283                             dev->crypto->encrypt ( dev->crypto, iob ) );
02284                 return;
02285         }
02286 
02287         net80211_set_state ( dev, NET80211_WAITING, NET80211_AUTHENTICATED,
02288                              IEEE80211_STATUS_SUCCESS );
02289 
02290         return;
02291 }

static void net80211_handle_assoc_reply ( struct net80211_device dev,
struct io_buffer iob 
) [static]

Handle receipt of 802.11 association reply frame.

Parameters:
dev 802.11 device
iob I/O buffer

Definition at line 2339 of file net80211.c.

References ieee80211_frame::addr3, net80211_device::aid, net80211_device::bssid, ieee80211_frame::data, io_buffer::data, DBGC, ETH_ALEN, ieee80211_assoc_resp, IEEE80211_STATUS_SUCCESS, memcpy, NET80211_ASSOCIATED, net80211_process_capab(), net80211_process_ie(), net80211_set_state(), NET80211_WAITING, and io_buffer::tail.

Referenced by net80211_handle_mgmt().

02341 {
02342         struct ieee80211_frame *hdr = iob->data;
02343         struct ieee80211_assoc_resp *assoc =
02344                 ( struct ieee80211_assoc_resp * ) hdr->data;
02345 
02346         net80211_process_capab ( dev, assoc->capability );
02347         net80211_process_ie ( dev, assoc->info_element, iob->tail );
02348 
02349         if ( assoc->status != IEEE80211_STATUS_SUCCESS ) {
02350                 DBGC ( dev, "802.11 %p association failed: status %d\n",
02351                        dev, assoc->status );
02352                 net80211_set_state ( dev, NET80211_WAITING, 0,
02353                                      assoc->status );
02354                 return;
02355         }
02356 
02357         /* ESSID was filled before the association request was sent */
02358         memcpy ( dev->bssid, hdr->addr3, ETH_ALEN );
02359         dev->aid = assoc->aid;
02360 
02361         net80211_set_state ( dev, NET80211_WAITING, NET80211_ASSOCIATED,
02362                              IEEE80211_STATUS_SUCCESS );
02363 }

static int net80211_send_disassoc ( struct net80211_device dev,
int  reason,
int  deauth 
) [static]

Send 802.11 disassociation frame.

Parameters:
dev 802.11 device
reason Reason for disassociation
deauth If TRUE, send deauthentication instead of disassociation
Return values:
rc Return status code

Definition at line 2374 of file net80211.c.

References alloc_iob(), net80211_device::bssid, EINVAL, ieee80211_disassoc, IEEE80211_STYPE_DEAUTH, IEEE80211_STYPE_DISASSOC, IEEE80211_TYP_FRAME_HEADER_LEN, iob_put, iob_reserve, NET80211_ASSOCIATED, net80211_set_state(), net80211_tx_mgmt(), and net80211_device::state.

Referenced by net80211_deauthenticate(), and net80211_netdev_close().

02376 {
02377         struct io_buffer *iob = alloc_iob ( 64 );
02378         struct ieee80211_disassoc *disassoc;
02379 
02380         if ( ! ( dev->state & NET80211_ASSOCIATED ) )
02381                 return -EINVAL;
02382 
02383         net80211_set_state ( dev, NET80211_ASSOCIATED, 0, 0 );
02384         iob_reserve ( iob, IEEE80211_TYP_FRAME_HEADER_LEN );
02385         disassoc = iob_put ( iob, sizeof ( *disassoc ) );
02386         disassoc->reason = reason;
02387 
02388         return net80211_tx_mgmt ( dev, deauth ? IEEE80211_STYPE_DEAUTH :
02389                                   IEEE80211_STYPE_DISASSOC, dev->bssid, iob );
02390 }

static void net80211_handle_mgmt ( struct net80211_device dev,
struct io_buffer iob,
int  signal 
) [static]

Handle receipt of 802.11 management frame.

Parameters:
dev 802.11 device
iob I/O buffer
signal Signal strength of received frame

Definition at line 2451 of file net80211.c.

References ieee80211_frame::data, io_buffer::data, DBGC, ieee80211_frame::fc, free_iob(), ieee80211_disassoc, IEEE80211_FC_SUBTYPE, IEEE80211_FC_TYPE, IEEE80211_STYPE_ACTION, IEEE80211_STYPE_ASSOC_REQ, IEEE80211_STYPE_ASSOC_RESP, IEEE80211_STYPE_AUTH, IEEE80211_STYPE_BEACON, IEEE80211_STYPE_DEAUTH, IEEE80211_STYPE_DISASSOC, IEEE80211_STYPE_PROBE_REQ, IEEE80211_STYPE_PROBE_RESP, IEEE80211_STYPE_REASSOC_REQ, IEEE80211_STYPE_REASSOC_RESP, IEEE80211_TYPE_MGMT, net80211_device::keep_mgmt, net80211_rx_info::list, io_buffer::list, list_add_tail, net80211_device::mgmt_info_queue, net80211_device::mgmt_queue, NET80211_ASSOCIATED, NET80211_AUTHENTICATED, net80211_autoassociate(), net80211_handle_assoc_reply(), net80211_handle_auth(), NET80211_IS_REASON, net80211_set_state(), net80211_update_link_quality(), net80211_rx_info::signal, net80211_device::state, u16, and zalloc().

Referenced by net80211_rx().

02453 {
02454         struct ieee80211_frame *hdr = iob->data;
02455         struct ieee80211_disassoc *disassoc;
02456         u16 stype = hdr->fc & IEEE80211_FC_SUBTYPE;
02457         int keep = 0;
02458         int is_deauth = ( stype == IEEE80211_STYPE_DEAUTH );
02459 
02460         if ( ( hdr->fc & IEEE80211_FC_TYPE ) != IEEE80211_TYPE_MGMT ) {
02461                 free_iob ( iob );
02462                 return;         /* only handle management frames */
02463         }
02464 
02465         switch ( stype ) {
02466                 /* We reconnect on deauthentication and disassociation. */
02467         case IEEE80211_STYPE_DEAUTH:
02468         case IEEE80211_STYPE_DISASSOC:
02469                 disassoc = ( struct ieee80211_disassoc * ) hdr->data;
02470                 net80211_set_state ( dev, is_deauth ? NET80211_AUTHENTICATED :
02471                                      NET80211_ASSOCIATED, 0,
02472                                      NET80211_IS_REASON | disassoc->reason );
02473                 DBGC ( dev, "802.11 %p %s: reason %d\n",
02474                        dev, is_deauth ? "deauthenticated" : "disassociated",
02475                        disassoc->reason );
02476 
02477                 /* Try to reassociate, in case it's transient. */
02478                 net80211_autoassociate ( dev );
02479 
02480                 break;
02481 
02482                 /* We handle authentication and association. */
02483         case IEEE80211_STYPE_AUTH:
02484                 if ( ! ( dev->state & NET80211_AUTHENTICATED ) )
02485                         net80211_handle_auth ( dev, iob );
02486                 break;
02487 
02488         case IEEE80211_STYPE_ASSOC_RESP:
02489         case IEEE80211_STYPE_REASSOC_RESP:
02490                 if ( ! ( dev->state & NET80211_ASSOCIATED ) )
02491                         net80211_handle_assoc_reply ( dev, iob );
02492                 break;
02493 
02494                 /* We pass probes and beacons onto network scanning
02495                    code. Pass actions for future extensibility. */
02496         case IEEE80211_STYPE_BEACON:
02497                 net80211_update_link_quality ( dev, iob );
02498                 /* fall through */
02499         case IEEE80211_STYPE_PROBE_RESP:
02500         case IEEE80211_STYPE_ACTION:
02501                 if ( dev->keep_mgmt ) {
02502                         struct net80211_rx_info *rxinf;
02503                         rxinf = zalloc ( sizeof ( *rxinf ) );
02504                         if ( ! rxinf ) {
02505                                 DBGC ( dev, "802.11 %p out of memory\n", dev );
02506                                 break;
02507                         }
02508                         rxinf->signal = signal;
02509                         list_add_tail ( &iob->list, &dev->mgmt_queue );
02510                         list_add_tail ( &rxinf->list, &dev->mgmt_info_queue );
02511                         keep = 1;
02512                 }
02513                 break;
02514 
02515         case IEEE80211_STYPE_PROBE_REQ:
02516                 /* Some nodes send these broadcast. Ignore them. */
02517                 break;
02518 
02519         case IEEE80211_STYPE_ASSOC_REQ:
02520         case IEEE80211_STYPE_REASSOC_REQ:
02521                 /* We should never receive these, only send them. */
02522                 DBGC ( dev, "802.11 %p received strange management request "
02523                        "(%04x)\n", dev, stype );
02524                 break;
02525 
02526         default:
02527                 DBGC ( dev, "802.11 %p received unimplemented management "
02528                        "packet (%04x)\n", dev, stype );
02529                 break;
02530         }
02531 
02532         if ( ! keep )
02533                 free_iob ( iob );
02534 }


Generated on Tue Apr 6 20:01:57 2010 for gPXE by  doxygen 1.5.7.1